Optimizing ASP.NET web pages

With increasing usage of mobile devices for browsing the web, optimization of web pages has become a topic of utmost importance. Perhaps, this post is nothing more than stating the obvious, as techniques to be mentioned here are very well known for quite some time, yet, pretty often ignored or dismissed, leaving web pages bad performance.

In this post, I am going to describe some of the well known techniques for web page optimization and how they can be leveraged in ASP.NET web pages/applications. This post will cover:

  • Javascript/CSS placements
  • Bundling & Minification
  • Caching
  • Image optimization
  • Gzip compression
  • Number of requests
  • CDN

Let’s get deeper into the topic.

JavaScript and CSS placement

It is often encountered that developers leave all CSS links and JavaScript (JS) references at the Head section of a page. Interpretation of the HTML code by the browser goes in a sequential way, so the browser downloads resources as they come, and until resource in the queue is downloaded, it stops downloading other resources if they are at the same host. As such, when source hits JS reference, it will block loading further until these JS files are downloaded. In most cases, JS files contain code related to functionality, and it is acceptable that functionality not to be available until the whole site is loaded.
Whilst, CSS files are required for proper appearance of the site. This suggests us, that CSS files usually have a higher priority for loading than JS files. As such, if we leave all CSS links at head section, and move all JS references at the bottom of the page, right before the body end tag, we will make the page appear before the whole site is loaded, thus giving a faster load time impression.

E.g.


<html lang="en">
<head>
<link type="text/css" reference="stylesheet" src="~/styles/style1.css"/>
<link type="text/css" reference="stylesheet" src="~/styles/style2.css"/>
<link type="text/css" reference="stylesheet" src="~/styles/style3.css"/>
</head>
<body>
...
</body>
</html>

Bundling & Minification

Bundling is a technique used to collect all CSS files into one CSS file, and all JS files into a one JS file. ASP.NET as of version 4.5 has bundling and minification functionality included. Older versions can get System.WebOptimization packag by downloading it from NuGet.

When you create a new MVC 4 web application from Visual Studio, you get bundling and minification set up by default. Bundling and minification code can be found in App_Start folder within the solution, in BundleConfig.cs file. Here you may add files to be bundled and minified one by one by registering them with their relative path like this:

bundles.Add(new ScriptBundle("~/bundles/libs").Include("~/Scripts/libs/jQuery.js"));

This code creates a virtual path “~/bundles/libs” and includes JavaScript file jQuery.js. You can include as many files as you wish, and they will be bundled in the order you have included them. You can also specify a pattern to include such asĀ "~/Scripts/libs/*.js" and this will include all JavaScript files in that folder. In the case of pattern, files will be loaded alphabetically, with consideration of known libriaries, such as jquery will be loaded before your custom libraries, and before jquery.UI.

It is important to note that, bundling and minification will happen only when the application is on “Release” solution configuration. When in debug mode, bundling and minification will not happen.

Caching

Caching is a technique used to create a temporary faster storage of commonly used content. Caching can be done on two levels:

  • Server side
  • Client side

When done server side, we load commonly used content to memory, and serve from that place instead of other sources such as HDD, DB, etc. ASP.NET provides support for server side caching through HttpContext.Current.Cache. However, server side cache helps with dynamic content. On the other side, a good part of web page load comes from static content such as JavaScript/CSS files, images, etc. Static content can be cached on client side. By this, we tell the browser what content can be saved locally for some time, and until that date is expired, the browser should not ask the server for that content. We can influence client caching through using a Manifest file or by saying the IIS to write caching headers on responses for static content. This can be done by adding this code in Web.config file.


<system.webServer>
<staticContent>
<clientCache cacheControlMaxAge="365:00:00" cacheControlMode="UseMaxAge"/>
</staticContent>
</system.webServer>

This will tell the client to cache static content for a year from the date of request.

Image optimization

Optimizing images is a crucial point on web optimization. Most of the sites today have a lot of images, and by optimizing them a lot of page load size can be saved. Images can be optimized by using a image editing software. From Visual Studio, an extension called Image Optimizer can be used to optimize images.

Image optimizer extension for Visual Studio

This extension will allow you to right click an image, or an image folder and select Optimize images option, and it will do the optimization for you.

Gzip compression

Gzip compression is a server side functionality for compressing the content sent to a client. By default, compression is enabled from IIS7.5 and above. If compression is enabled on web server, then we can influence this behavior from web config by specifying this:

<system.webServer>
<urlCompression doDynamicCompression=”true”
doStaticCompression=”true”
dynamicCompressionBeforeCache=”true”/>
</system.webServer>

If values are specified to false, then this will stop compression.

If you are using IIS Express, then you can activate compression by executing this command from iis express folder

appcmd set config -section:urlCompression /doDynamicCompression:true

Number of requests

By HTTP specification, the browser should download at most 2 resources in parallel from the same host. Most browsers comply with this, or up to 4 parallel downloads. This means, if there is a high number of requests to retrieve the whole site, the page load time will be slow.

This bottleneck can be addressed in different ways. Bundling & minification is one way to decrease the number of requests. CSS Sprites as well as embedding small background images to CSS also will help on this. One other way to help this is by putting resources in different hosts. Even subdomains will help on this, for e.g. putting images, scripts, and css on different subdomains like this:

images.host.com
scripts.host.com
css.host.com

will make the browser believe it is downloading files from different resources and throw more threads for parallel downloads.

Content Delivery Networks (CDNs)

CDN is a way to optimize a web page as well as save bandwidth at the same time. Most common libraries used, one of them being jQuery, are hosted by CDN providers such as Microsoft, Google, etc. You can even use custom CDNs such as Akamai and host your content.

CDNs will optimize content download from a geographically close location to the requester. This will also benefit from the fact that the browser will see a different host from your side, and will throw another thread for downloading content from CDN.

The techniques mentioned in this post are by no means all what can be done to optimize ASP.NET web pages. There are many other techniques with more specific usage and help optimization of web pages.

Zen Coding

Zen Coding is a plugin for HTML, XML, XSL, CSS fast code editing which could be used in different text editing software and/or IDEs. Recently, through the Web Essentials VS Extension, Zen coding is also available in Visual Studio. This functionality is activated by pressing TAB key right after you write the zen code.

Zen coding has a specific syntax, and the code is created by combining html tags and ‘zen code operators’. These operators include :

Operator Operation
# Create ID attribute
> Child element
. CSS style
* Mutiplication of elements
[] Custom attribute
+ Sibling element
^ Climbs one hierarchy level up

Let’s demonstrate these by examples.

Specifying the ID

If we want to create a div element which has an id named container, then we would write

div#container and when we press TAB, and the result will be <div id="container"></div>

Creating child elements

If we want to create nested elements, then we would use greater then (>) symbol to specify nested elements. Writing ul>li produces

<ul>
<li></li>
</ul>

with proper indentation.

Adding CSS class to element(s)

The dot symbol will add css class to an element. Modifying the last example code to ul#menu>li.menuItem will produce

<ul id="menu">
<li class="menuItem"></li>
</ul>

Creating many elements

If we want to create more than one element of the same type, then we will use multiplier (*) operator. If we write ul#menu>li.menuItem*5 the result will be

<ul id="menu">
<li class="menuItem"></li>
<li class="menuItem"></li>
<li class="menuItem"></li>
<li class="menuItem"></li>
<li class="menuItem"></li>
</ul>

Creating custom attributes

In some cases, there is a need for custom attributes (e.g. new html data-dash attributes). Let us modify our last example so it includes a data-value attribute. If we write ul#menu>li[data-value].menuItem*5 and press TAB, the result will be


<ul id="menu">
<li data-value="" class="menuItem"></li>
<li data-value="" class="menuItem"></li>
<li data-value="" class="menuItem"></li>
<li data-value="" class="menuItem"></li>
<li data-value="" class="menuItem"></li>
</ul>

We can even give a default value to the attribute by changing attribute section to [data-value=val].

Creating sibling elements

Let us create a div for search with an id equal to ‘search’ and two input elements inside, one textbox and one search button. Our zen code would look like this:

div#search>input[type=text]+input[type=submit,value=search]

and it will produce

<div id="search">
<input type="text" value="" />
<input type="submit" value="search" />
</div>

Level up

The caret operator (^) enables us to go one level up in hierarchy. E.g.

CodeĀ div#container>div#element1^div#element2 will produce this HTML

<div id="container">
<div id="element1"></div>
</div>
<div id="element2"></div>

This is it folks. I hope you like it.