Tag Archives: ASP.NET

ASP.NET 1.1 pages/assemblies take a long time on first load

The first time you load a page on an ASP.NET web site, or the first time you access a .NET web service, it may take significantly longer to load than subsequent accesses. There are several things that can cause this, including the framework compiling the aspx source pages, but there can be an even more significant delay if you are using Authenticode-signed assemblies and your server does not have access to the internet. In the case of web services, this delay may even be long enough to cause timeouts depending on the configuration of your client programs.

The problem is that as .NET loads Authenticode signed assemblies, it must check for updates on the certificate revocation list (CRL) to verify the signature on the assembly is valid. If Active Directory is not configured to have the authority for CRLs on the local network and the server in question does not have a connection to the internet, the request for the CRL will time out after approximately 15 seconds, and .NET will continue loading the assembly and consider it to be unsigned. This problem is discussed in several articles.

To verify this is what’s happening, you can use a packet sniffer on the server in question and look for the request for the CRL. Using Wireshark, I was able to observe the following behavior after I had stopped the World Wide Publishing service, started the trace, relaunched the World Wide Publishing service, and made a request:

Request for CRL

Request for CRL

The above screenshot shows that a request was made for http://crl.microsoft.com/pki/crl/products/CodeSignPCA2.crl (IP address 96.17.76.91).

Note that the request will not always be made. The CRL is always cached for the lifetime of a process, so if the IIS worker processes continue to run you will not get a request for the CRL. It’s possible that the CRL is cached for longer, though I haven’t been able to verify that this Microsoft Technet article describes many things about the Windows PKI, including CRL caching. I can replicate the above results when I first stop the World Wide Publishing service, clear the cached data from Internet Explorer, start the trace, start the World Wide Publishing, then make a request to the ASP.NET page/web service. For computers that are not connected to the internet and have not been for a long time, I would guess any caching for the CRL would expire, and every time an Authenticode signed assembly is loaded Windows would try to refresh the CRL. On Vista, you can explicitly refresh the CRL cache per this article.

Resolving this issue on .NET 2.0 post SP1 is straightforward. Setting the generatePublisherEvidence configuration option to false will skip the CRL check. This issue is discussed in Microsoft KB936707.

On .NET 1.1, things are not as straightforward. There isn’t a configuration setting to disable the authentication behavior. The only solution is to disable CRL checking for the entire machine. This can be accomplished through the following steps, originally described on this website.

  1. Open Internet Explorer
  2. Go to Tools —> Internet Options…
  3. Go to the Advanced tab
  4. Locate the Security section and uncheck the Check for publisher’s certificate revocation option.
    Disable Check for publisher's certificate revocation option.

    Disable Check for publisher's certificate revocation option.

CRL checking can also be disabled throughout the entire organization per this Microsoft Technet article.

Another option to address the symptoms as opposed to the underlying issue is to change the behavior of the IIS worker processes. As mentioned previously, the CRL is cached throughout the lifetime of a process, so by managing the lifecyle of the worker process, you can force this timeout to come during non-work hours.

In IIS manager, view properties for the app pool under which your ASP.NET application is running. Go to the Performance tab and disable the idle timeout of the worker processes.

Disable worker process idle timeout

Disable worker process idle timeout

Next, go back to the Recycling tab and set the processes to only recycle at a certain time of day (e.g. 2:00 a.m.).

Change app pool recycling to non-business hours

Change app pool recycling to non-business hours

The last step is to create a custom script that will make a request to your application shortly after the worker processes have been recycled. This will force the CRL check at a time when it doesn’t matter how long the first request takes as normal user activity won’t be interrupted.

Double Hop Problem

Those of you who work with ASP.NET and IIS’s Integrated Authentication feature may also be familiar with impersonation. Impersonation allows the thread processing the ASP.NET request to operate on the local server as the user who has been authenticated. This sounds really great, and there are some nice advantages to this situation, but the problem is that this user impersonation does not continue if you connect to additional servers. So this means that you can’t give the end user’s account access to a separate SQL Server box, and expect that the impersonation will allow the ASP.NET code to access the database.

Those of you familiar with what’s happening with Kerberos under the hood will probably not need a lot of discussion on the topic, but for those where this is a new problem, here is a good MSDN blog post about the topic discussing the problem and implications.