A few days ago I was talking to a network administrator that had some issues with his management websites. He explained to me that they were all using ASP.NET and he clearly did not like the fact that they were. I expected some kind of rant about how bad ASP.NET is and how fast PHP is, but instead of doing that he asked me if I could show him some tricks to make things run faster. I already explained a few to him, but I think it also makes a great blog post. So here it goes.
One of the biggest issues with ASP.NET pages are the startup times of the web application. When a user first accesses a page that hasn’t been used for a while the page gets pre-compiled by the ASP.NET pre-compiler and then compiled to a native image by the JIT compiler. This is a rather slow process with bigger pages, so the user may have to wait a couple of seconds before the page shows up.
Pre-compiling the website
There are basically two things that you can do to speed things up. The first is pre-compiling the website. The pre-compiling process can be done by executing the following command-line:
%windir%Microsoft.NETFrameworkv2.0.50727aspnet_compiler.exe –v /VirtualPathToTheWebsite D:ProjectsSomeWebAppOutput -u
This will pre-compile all the pages and place the results in the specified output directory. Once you have precompiled the website you can deploy the contents of the output directory to IIS.
A big advantage here is the cut in boot times, the downside is that you need to do this each time a new version is deployed. Also keep in mind that you use the –u switch otherwise the website cannot be updated with a new precompiled version and you will have to remove all files from the deployment and copy a new precompiled version in place.
Generating native images
While pre-compiling already improves startup times considerably there’s one extra step that you can take to make the website even faster. By generating native images of a .NET assembly it gets compiled specifically for your computer so that the JIT compiler doesn’t have to do that on startup.
Generating native images is done by executing ngen.exe install <assemblypath> on every assembly that exists in the bin folder of the website. There’s no need to have a strong name on them, so the App_Web_xxxxx.dll file can also be installed as a native image.
Generating native images does speed up the website, but only by a very small amount. It works best when shared libraries like the Microsoft Enterprise Library are installed as native images. Once one website has loaded these assemblies the next website doesn’t need to load them again,thus speeding up the startup process. When you want to improve the speed of your website in a cold start scenario you’re better off buying a solid state disk and pre-compiling the ASP.NET web pages.
Pre-warming your application
On top of the options provided here ASP.NET 4 offers more options to speed up the startup process of your web application. One of them is the always running option that’s new in ASP.NET 4. It allows developers to register a special provider that preloads data when the application is started. When the application is deployed to IIS it will get started directly and the custom startup provider gets invoked to preload the data required by the application.
Check out the following link for more information: http://msdn.microsoft.com/en-us/library/s57a598e(VS.100).aspx#aspnet_core_services
Once the website is started and all the pages have been pre-compiled all that remains is the runtime performance, the speed at which output of the pages is generated that is. There are many ways to improve the performance of your ASP.NET pages when looking at the speed at which the output is generated. Here’s a few tips to speed up the performance of your website even further.
Use output caching
Some pages contain data that doesn’t need to smell as if the bits have just been cooked up by the processor. The data on the page can be a couple of days old and might not change over the coming few days. When it also doesn’t matter if the user sees data that was valid 20 minutes ago, it might be a good idea to use output caching on that page. This allows the webserver to cache the output of the webpage and send that output back to every user that requests the page in the 20 minute window after the page was cached.
Doing this not only speeds up the application, but also can reduce the load on the webserver because it only needs to send back HTML and images instead of executing complex code to generate that HTML and then send that to the user.
The downside to this is that it doesn’t work for pages that need that really fresh data. However when used correctly this does make users very happy.
New in ASP.NET 4 is the possibility to extend the behavior of the output cache. This can be done by making use of an OutputCacheProvider implementation. There’s a ton of possibilities here, so keep an eye out for the new version of ASP.NET!
In the case where the data needs to be really fresh there’s another trick to still make things faster. I call this partially data caching. There’s data that needs to be absolutely fresh, but there’s a ton of other data for which it’s acceptable that it is a bit older.
Take a close look at the the data you’re loading into the page and consider whether some of it can be cached in the ASP.NET cache for later use. It doesn’t save quite as much performance as output caching, but it still helps.
Despite the fact that we have some pretty hefty hardware these days to run our websites it’s still a good idea to take a good look at the performance of the website you are building. That little bit of extra attention can make a world of difference to users.
For more information about the various topic in this post check out the following links.
- Output caching: http://msdn.microsoft.com/en-us/library/06bh14hk.aspx
- ASP.NET 4 output cache extensibility: http://msdn.microsoft.com/en-us/library/s57a598e(VS.100).aspx#aspnet_core_services
- Pre-compiling a website: http://msdn.microsoft.com/en-us/library/ms227976.aspx
- Native image generator: http://msdn.microsoft.com/en-us/library/6t9t5wcf(VS.80).aspx