Uncategorized

Is your UserControl sluggish at loading?

Here’s an interesting story about performance I had the chance to work on over the last couple of weeks. The object of the call was a UserControl embedded in Internet Explorer, which was very slow to load the first time you browsed the page, but then was performing quite well after that long delay (around 60 seconds); unfortunately closing and reopening the browser caused another 60 seconds delay, which was quite bothering if not frustrating for end users… As you can imagine the control needs to be downloaded, JIT compiled and loaded which of course requires some time depending on how big is the control, how fast (or slow) the Internet connection, how powerful the client etc…, but those 60 seconds where definitely too much. Moreover on Vista we were prompted to run csc.exe and under some circumstances (usually if IE was not run as Administrator) we got a FileNotFoundException.

Probing

First thing, Fiddler showed that after downloading the first dll (the actual UserControl) we were probing for further localized resources, so we wasting about 15 seconds just for this reason (which is a quarter of the entire time spent waiting on a white IE page…). At the same time Process Monitor showed (as expected) that some time was needed to JIT the control but also to create on the fly the serialization proxy assembly, which the UserControl needed to call a remote Web Service and get the data to show to the user.

There are different possible approaches to the problem, but in this case we had some constraints imposed by the hosting company the customer was using to test his application, so to work around those limitations we first removed the strong name from the two assemblies because it was not a strict security requirement in this case and because strong named assemblies are prone to probing (as you may know, one of the token in a strong name is the culture information). Then we specified the NeutralResourceLanguageAttribute to tell the ResourceManager to not search for resources that are included in the main assembly; when looking up resources in the same culture as the neutral resources language, the ResourceManager automatically uses the resources located in the main assembly, instead of searching for a satellite assembly with the current user interface culture for the current thread. This will improve lookup performance for the first resource you load, and can reduce your working set. As a final step we added an empty file (zero bytes) in the first places where the runtime was probing; this because the NeutralResourceLanguageAttribute resolved the problem for me (I was testing with an English OS) but not for the customer whom was using a non English OS…

Serialization assembly

As you can see from the screenshot here, the runtime was also probing for <assemblyname>.XmlSerializers.dll which is the proxy needed to call the remote Web Service (and which needs to be created on the fly, as Process Monitor shown); so in this case we used sgen.exe to pre-generate the serialization assembly we could put on the server in the same folder of the UserControl. This serialization assembly is downloaded by the browser and therefore there is no need to create it on the client, so we removed both the security prompt (and the exception) and the delay to create the proxy on the client.

In short, after applying those changes the time taken from the first HTTP request to the UserControl fully loaded and functioning on the client went from about 60 seconds to just 5! ?

There is a nice article from Chris Sells on the subject, it’s 5 years old but still gives some interesting insight on probing and how serve related files (like .config etc…).

Specify a codeBase

Doing further researches for this post I found another couple of possible solutions to the problem. First it’s possible to specify a codeBase attribute in your web.config as described in http://support.microsoft.com/kb/814668/en-us (this applies also to .NET 1.1).

Or you can add a section to the web.config file telling the ResourceManager exactly which resources are present on the machine for each assembly.  Here’s an example:

   1: <?xml version="1.0"?>
   2: <configuration>
   3:     <satelliteassemblies>
   4:         <assembly name="mscorlib, Version=..., PublicKeyToken=...">
   5:             <culture>fr</culture>
   6:         </assembly>
   7:         <assembly name="UserAssembly, ...">
   8:             <culture>fr-FR</culture>
   9:             <culture>de-CH</culture>
  10:         </assembly>
  11:             <assembly name="UserAssembly2, ...">
  12:         </assembly>
  13:     </satelliteassemblies>
  14: </configuration>

Note that the assembly references in this example are abbreviated, and they will need to supply full assembly names.

Carlo

Quote of the Day:

For greed, all nature is too little.

–Seneca, Roman statesman and author

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.