Introduction
I know: the problem of pre-compiling an ASP.NET web site in order to avoid the classic "compilation delay" felt by the first user browsing those site's pages has been faced many times, and a lot of solutions have been proposed to solve it. But, when I was looking for these solutions to a classic problem, I didn't find the one that I liked completely. So, I decided to develop my own ASP.NET precompiler.
Of course, now you are thinking: "Uff, yet another pre-compile tool for ASP.NET web sites". And you're so right that I decided to title my article exactly with the words you have in your mind. But... before you stop reading, take a look at some peculiarities of the tool I propose.
Background
My starting point was the CodeProject article "Pre-Compile ASPX pages in .NET 1.1" by Narendra Naidu: there, the precompiling task was faced by simply adding to the web site a special ASP.NET page simulating an HttpWebRequest
towards each ASPX page of the web site itself.
That was a nice and simple solution, but not suitable in my specific situation. In fact, I was looking for:
- something not implemented as a part of the web site, but as a separate application;
- something not forcing me to precompile all the pages of my web site, but capable to focus only on a specific subset of them (for example, the most frequently used ones);
- something working also with web sites protected by the ASP.NET Web Form Authentication mechanism;
- something able to simulate client web requests coming from a specific browser;
- something with the ability to keep track of compilation errors.
The ASP.NET precompiler I wrote matches all these goals, in fact:
- it's a Windows Forms application, that doesn't force you to include the precompiler logic inside the web site itself;
- it doesn't retrieve the pages to visit recursively walking on the web application folders tree, but it takes them from a user-configurable list of URLs;
- it works also with web sites protected by Web Form Authentication, supporting a specific POST of data to the Login page and correctly managing the client-side authentication cookie;
- it can "impersonate" a specific user agent, allowing you to work also with sites where some browser checks are implemented to force a navigation restriction;
- it logs any error occurring during HTTP requests, that is very useful if - for some reason (for example, to have a more flexible deploying strategy) - you are not compiling your site's code-behind pages into a DLL assembly (that is: you're taking advantage of the
src
attribute of the @Page
directive).
How to use the tool
As stated before, the tool forces the compilation of ASPX files just invoking their URLs in a web request. The list of the URLs to be hit is stored in a user-editable text file, that we'll simply call "URL file". The format of the URL file is simple: it stores an URL on each line, separating with a TAB character the base URL part from the relative path of the ASPX page. This split URL paths make simpler to invoke the same set of pages on different web sites (this is useful, for example, if you have various copies of the same ASP.NET site on different environments).
To create the URL file, you can use ASP.NET precompiler itself: select the "Generate URLs" option from the "File" menu and specify: the physical location of your web site's files, the base URL that will precede the relative page path in the final URL, and the filename for your new URL file.

ASP.NET precompiler will walk recursively the specified path looking for ASPX files and it will generate your URL file, that can be manually edited later (for example, to refine or limit the set of pages to be precompiled).
To make the ASP.NET precompiler less "invasive" on your site, you can adopt a trick I found in Narendra Naidu's article: by adding a Response.End()
inside the pre-request event handler of Global.asax, you can abort the page processing and rendering when you call your pages with a special parameter (for example, PreCompile=true
). In this way, the requests coming from ASP.NET precompiler will cause the page compilation but not the complete overhead of serving a complete web request.
Private Sub Global_PreRequestHandlerExecute(...) _
Handles MyBase.PreRequestHandlerExecute
If Not Request("PreCompile") Is Nothing Then Response.End()
End Sub
If you are planning to use this trick, you'll need to check the "Include PreCompile parameter" option when generating the URLs list with ASP.NET precompiler. Also, keep in mind that the Global_PreRequestHandlerExecute()
handler will be invoked for each page requested on your web application, and this might cause a little impact on the web site performance.
When the URL file is ready, before starting the pre-compilation process, you need to configure some parameters on the ASP.NET precompiler's main form:

- specify the name of the URL file you are going to use;
- if you need to simulate web request from a specific browser, fill the textbox User Agent with the correct user agent string;
- if you plan to invoke the pages stored in the URL file substituting the original base URL path with another one, use the Alternative Web Root option;
- if the site you're working on is protected by Web Form Authentication, use the Web Form Authentication option, specifying the relative path for the Login page and the parameters it expects; activating this option will produce a preliminary POST request to the Login page to obtain the authentication cookie for subsequent requests (don't forget to include the
__VIEWSTATE
parameter with a valid value in the POST params textbox);
- if you want to log any error occurred during the compilation process, activate the Log errors option, specifying the filename for the log (that is an HTML-formatted file, for easy viewing in a browser window);
- if you need to clear the error log or the cookies collection before compiling, use the Reset cookies or the Reset error log option respectively.
The configuration settings you just set can be saved to disk for future use. The reuse of ASP.NET Precompiler settings is accomplished by the options of the "File" menu (for the storage mechanism underlying the saving/retrieval of these data, see my article about managing configuration settings persistence).