Omer van Kloeten's .NET Zen

Programming is life, the rest is mere details

News

Note: This blog has moved to omervk.wordpress.com.

Omer van Kloeten's Facebook profile

Omer has been professionally developing applications over the past 8 years, both at the IDF’s IT corps and later at the Sela Technology Center, but has had the programming bug ever since he can remember himself.
As a senior developer at NuConomy, a leading web analytics and advertising startup, he leads a wide range of technologies for its flagship products.

Get Firefox


powered by Dapper 

.NET Resources

Articles :: CodeDom

Articles :: nGineer

Culture

Projects

Help! My Web Application Throws an Insane Amount of TypeLoadExceptions!

One of the first things I noticed when I started debugging our web application was that at load I got an insane amount of these:

A first chance exception of type 'System.TypeLoadException' occurred in System.Web.dll
A first chance exception of type 'System.TypeLoadException' occurred in System.Web.dll
A first chance exception of type 'System.TypeLoadException' occurred in System.Web.dll
...

After digging into the code, I found out that during the loading process of controls, ASP.NET tries to find the type that matches a certain tag. The following code piece from System.Web.UI.NamespaceTagNameToTypeMapper (line 82):

Type type = null; 

// If loading the type from the assembly depends on a referenced assembly that cannot
// be loaded, we should throw the actual exception, instead of later reporting a more
// generic error saying the type was not found (Devdiv 138674) 
try {
    type = _assembly.GetType(typeName, true /*throwOnError*/, true /*ignoreCase*/); 
} 
catch (System.IO.FileNotFoundException) {
    throw; 
}
catch (System.IO.FileLoadException) {
    throw;
} 
catch (BadImageFormatException) {
    throw; 
} 
catch {
    // For all other exceptions, such as when the type is not present in the assembly, 
    // we ignore the exception so that we can continue to check other assemblies to look
    // for the type.
}
return type;

What the hell?! This is a horrible bottleneck!

What's the solution, you ask? Well, it's simple - just tell ASP.NET ahead of time where your controls are with the @ Register directive. For instance:

<%@ Register Assembly="System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A" 
             Namespace="System.Web.UI.WebControls" TagPrefix="wc" %>

This gives ASP.NET a little hint, telling it that if it wants controls with the wc tag prefix, it should look for them in the System.Web.UI.WebControls namespace in the System.Web assembly. Then all you have to do is to mark all of the controls that come from that namespace in that assembly with that specific prefix, as such:

<wc:Literal ID="Something" runat="server"></wc:Literal>

And that's that. No more annoying exceptions.

Make sure to use the full assembly name in the @ Register directive, otherwise you'll get a System.IO.FileNotFoundException thrown when ASP.NET can't find the assembly.

One more thing that's important to note is that if you have only a few of these, set your web.config's compilation element's batch attribute to false, which means ASP.NET will load pages on demand. This way you'll know the culprit page when you hit it for the first time, rather than have the exception thrown when the whole application starts.

[Update: An application-wide solution would be to use the system.web / pages / controls element in the web.config to declare prefixes for all of your controls, rather than at the single page level:

<configuration>
  <system.web>
    <pages>
      <controls>
        <add tagPrefix="wc" namespace="System.Web.UI.WebControls"
assembly="System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>

And thanks to Ofer Bar from my team for the tip.]

Comments

No Comments