Loading custom web control from an .aspx Code-Behind page
Yesterday one of our clients requested a simple change to a custom user control for one of their ASP.NET 2.0 site. We made the change, and deployed ONLY the .ascx file to their production server.
The deployment resulted in the following run-time error:
Unable to cast object of type ‘ASP.controls_customControl_ascx’ to type ‘controls_customControl’.
This error appeared to disappear by editing the webconfig file.
The structure of the control we edited was such that it dynamically loaded a second control in its code behind. This was done by making a reference to the custom control through the use of the @Register directive in the .ascx page.
<%@ Register src=”customControl.ascx” mce_src=”customControl.ascx” TagName=”CustomControl” TagPrefix=”uc1″ %>
In the code behind, the control was then loaded and explicitly cast to the appropriate type upon the click of a button in the control.
controls_customControl custom = (controls_customControl)LoadControl(”../controls/customControl.ascx”);
(NOTE: The dynamically loaded control inherits from a class defined in a precompiled assembly)
So what happen?
We all know that when the first request arrives for any page within a folder ASP.NET dynamically parses and compiles all the ASPX pages in that folder. We also know that it compiles any code-behind files associated with ASCX files into a separate assembly. If two pages exist in the same folder they will be compiled into the same assembly. Based on this understanding, I would have predicted that the file being changed would have been enough to trigger a recompile of the control folders assembly, eliminating the error.
Could the behavior come as a result of the @Register directive?
When you load a control programmatically the strong type for the control is available only after you have created a reference to it. By definition @Register is used for declarative inclusion of control in a page. The assembly referenced in the directive is dynamically created the first time the ASP.NET runtime accesses the resource. The instance of the control will be created “on-the-fly” when the page is loaded.
It has always been my understanding that when a programmer chooses to load a control in the code-behind, the strong type of the control is only available after the page has made reference to it, making @Register inappropriate. Without the implicit inclusion of the control in the page, the compiler should throw and error. I believe in our situation it worked because both controls exist in the same directory resulting in them being compiled into the same assembly.
Most documentation suggests that one should use the @Reference directive and NOT @Register when loading controls programmatically. @Reference tells .NET that the referenced control MUST be dynamically compiled and linked. If two controls in the same directory have dependencies on each other through an @Reference directive, they will end up in separate assemblies.
Would this have eliminated my error…time to do some testing!
….to be continued….

