Thursday, September 4, 2008

ASP.NET Site Warmup

UPDATE - 12/8/2011 - Project updated and moved to github

ASP.NET applications by nature exhibit some degree of delay upon initial access to the site. This is due to the nature of the JIT compilation, caching, etc - and most all ASP.NET websites of any size are going to exhibit some amount of delay on that first hit.

Now if you've ever done any admin work with Sharepoint, you've most likely used the Sharepoint-specific warmup script to eliminate Sharepoint's extremely annoying first-hit delay.

It was actually that script that got me thinking.. why not write a little app I can schedule to programmatically perform that first hit to any site(s) I want?

Sure, you could just plug an individual URL into a Scheduled Task and get the same effect - but this way just seemed a little cleaner to me.

Now there is nothing magic about the app. All it does is read in a list of sites from an xml file and perform an HTTP GET against them using an HttpWebRequest. The only thing even remotely out of the ordinary is that I included code to use the DefaultCredentials and also set the UserAgent.

I actually didn't realize it before this, but if you don't set the UserAgent and attempt to do a GET to a page that contains an AJAX .NET UpdatePanel - the page doesn't recognize the UserAgent and you'll get the wonderfully generic 500 System Error.

The heart of the code is this:


foreach (XmlNode node in xmlDoc.SelectNodes("Sites/Site"))
{
XmlElement url = (XmlElement)node;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url.SelectSingleNode("URL").InnerText);
request.Credentials = CredentialCache.DefaultCredentials;
request.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)";
WebResponse response = request.GetResponse();
response.Close();
Console.WriteLine(String.Format("{0} : Successful", url.SelectSingleNode("URL").InnerText));
}


To use, simply plug your sites into the sites.xml file and schedule the app to run as a Scheduled Task.

You may also run the exe with any normal help trigger (/h or /? or -? or etc..) for more information.

12 comments:

  1. Hi there... where can we download the EXE of this script?

    ReplyDelete
  2. Tommy-
    I guess I didn't realize the compiled .exe wasn't included in the solution files.

    I've updated the zip to include it now.

    It's in the bin\Release folder.
    Thanks-

    ReplyDelete
  3. This is exactly what i was looking for! Thanks for sharing your code...

    ReplyDelete
  4. Nice...Worked better than I expected.

    ReplyDelete
  5. And what about if your pages require passwords?

    ReplyDelete
  6. User420667-
    Good point. It'd only take a minor change to allow the user and pw to be set in the XML. Unfortunately it'd be plain text but I guess itd be better than nothing. I just run it under the credentials of a domain account that has access to the sites (integrated auth in intranet environment). I'll look at updating to handle basic auth as well. Thanks-
    Kenneth

    ReplyDelete
  7. Please notice the project has been moved to a github repository. All files are available there.
    Thanks-

    ReplyDelete
  8. I had the same in ruby on rails application with passenger but I found a nice tool ( http://www.wekkars.com ) that just prevents the webserver to go to sleep.

    ReplyDelete
  9. Works nice, however... if one of the sites in the list is down (error 404 - not found), then the program just stops...
    I think it should continue and process the rest of the sites in the xml file.

    Regards,
    M.R.

    ReplyDelete
  10. Hello, I just want to point a easyer solution :

    in IIS, go to your application pool, advanced settings and set idle timeout to 0. Same result, no additionnal software, cleaner.

    Enjoy

    ReplyDelete
  11. Great article Kenneth! I was wondering, if you had to request the same website on multiple servers, how would you go about that? The only option that comes to mind is editing you hosts file each time to a different IP address. Much appreciated

    ReplyDelete