On my previous post about the dubious “Ambiguous match found” exception, I talked about the fact that the ASP.NET runtime is case sensitive and if you are writing in C# you better be careful about how you name your private, protected and public variables.
Not so long ago, I’ve encountered another problem which is relatively similar. It manifests itself in the runtime but it is actually related to the ASP.NET compiler.
When first accessing an ASPX page in an application after the server was started, the ASP.NET runtime will try to compile that page. One of the first steps in doing so is to parse the ASPX page and figure out what controls were placed on it. It will then create these controls and the Page object behind the page and render the page outputting the result back to the client.
When the ASP.NET runtime tries to create the various controls placed on the ASPX page, it will use the GetType function, but for some reason, it will only pass the name of the control and not its full namespace.
In my case, we had a custom user control named HtmlAnchor which was suppose to overcome a few quirks with HTML anchors in some browsers. ASP.NET already contains a control named HtmlAnchor which its full namespace is System.Web.UI.HtmlControls.HtmlAnchor.
Our control, had no namespace, since we simply created a user control in our application.
Even though we didn’t use even a single System.Web.UI.HtmlControls.HtmlAnchor, but only our custom HtmlAnchor control we got a strange error about not being able to load a certain .NET assembly which was suppose to be generated when the page first renders to produce the page’s code cache.
I fired up WinDbg and when the exception occurs, search for objects of type CompilerError by issuing:
!dumpheap -type CompilerError
This will list all CompilerError objects in the heap. After that I issued:
Where 0xXXXX is the address of the CompilerError object that I’m inspecting (!do = !dumpobject)
And inside there is a private member that contains the error text which I also dumped (using !do).
The error that I saw was that .NET cannot cast HtmlAnchor (my HtmlAnchor) to System.Web.UI.HtmlControls.HtmlAnchor.
I issued “!clrstack -p” to see the call stack and the parameters that were passed to each function and along the way there was call to GetType with the name parameter that was equal to “HtmlAnchor”.
This was the problem. For some reason .NET figured out that my HtmlAnchor is suppose to be the HtmlAnchor the resides in System.UI.HtmlControls.
As it turns out, the namespace System.UI.HtmlControls is ALWAYS included when the ASP.NET compiler compiles an ASPX page and, for some reason, request the type of the object WITHOUT its full namespace and find the wrong HtmlAnchor even though I have a different TagPrefix for my HtmlAnchor in the ASPX page.
The is a combination of a number of problems.
First, when adding a user control to an ASP.NET web application, there is no specific namespace in the file. It will eventually get the namespace of ASP.XXXX when compiled using the ASP.NET compiler like the rest of the ASCX and ASPX pages.
I haven’t checked it for user controls that are not ASCX, meaning, someone wrote a control in some DLL and does get a namespace. The difference is that when including that control on an ASPX page we do provide the exact namespace and assembly, so it might works without a problem.
Second, if the user control has the same name as any of the control that are in the System.Web.UI.HtmlControls and System.Web.UI.WebControls namespaces, they will, for some reason, get loaded in GetType instead of your controls.
Third, in the @Register tag at the top of the page, where we declare and include our user control (we include the ASCX file), there is no additional information such as namespace to help the ASP.NET compiler resolve this issue.
Be careful when you name your User Controls (ASCX controls) and make sure they do not have the same name as other controls in System.Web.UI.*.