Registering UserControls in web.config, and Handling Nested UserControls

As I recently migrated an ASP.Net Web Site Project to a Web Application Project, I also tried to “clean up” the markup files by

  • moving the registration of the project’s UserControls from the aspx/ascx markup to the web.config configuration file
  • and naming the UserControls’ tagName and tagPrefix values consistently

Visual Studio (2008) compilation was successful, and even aspnet_compiler did not complain. The errors only started to occur upon hitting Run.

The page ‘/Default.aspx’ cannot use the user control ‘/WebUserControl.ascx’, because it is registered in web.config and lives in the same directory as the page.

Die Seite “/Default.aspx” kann das Benutzersteuerelement “/WebUserControl.ascx” nicht verwenden, weil es in “web.config” registriert ist und sich im gleichen Verzeichnis befindet wie die Seite.

I found an acknowledgement of this behavior in an MS Connect entry:

Posted by Microsoft on 5/26/2005 at 11:03 PM
Ideally, this would work, but there are some issues with the internal implementation that makes this scenario non-trivial to support. We will look into removing this restriction in a future version. The best thing to do is to put the user controls in their own folder.

My steps to resolve this error were:

  • Move the UserControls registered in the web.config file to a separate directory
  • If you have nested UserControls, the you need to split them into different directories

In the current project, I ended up with this directory structure:

/Controls common user controls
/Controls2 common user controls containing user controls of /Controls directory
/Menus menu user controls
/Menus2 nested menu user controls containing menu controls of /Menus directory

One consequence of moving UserControls to a directory is that any HyperLinks in those UserControls now include the control’s directory name in the HyperLink URL if you use relative paths.

This can be fixed by setting the UserControls’ AppRelativeTemplateSourceDirectory property correctly:

        protected override void OnInit(EventArgs e)
            AppRelativeTemplateSourceDirectory = "~/";

If you use relative URL’s and your application files are laid out in a directory tree, have a look at this answer on StackOverflow.

There are of course occurrences of LoadControl(“foo.ascx”) in a couple of places which are affected by this UserControl migration. So what about using LoadControl(Type, Object[]) instead, and have the framework look up the control by its type name?

Computer says No.

If the UserControl contains other controls (which they usually do), then the child controls are not initialized by the LoadControl(Type) method (or at least this is what I understood from this explanation):

This is by-design since the type “TestUC” is actually the base type used by the partial class, it does not contain the proper code to instantiate TextBox1 reference, which is actually defined in the derived type. There are two workarounds: 1. Use LoadControl(“TestControl.ascx”), for all practical, this behaves identically to LoadControl(type) but it instantiates the derived type, which knows how to instantiate TextBox1. 2. Use a single file page and adds <%@ Reference %> directive to the page to reference the user control, and assign a classname to the ascx page. Then it’s safe to use LoadControl(type).

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

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