RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Compilation and Deployment in ASP.NET 2.0 : Page 6

Compilation and deployment are key features that ASP.NET developers should understand quite well. Find out how the process works and what options are available to compile and deploy your applications effectively.

Referencing Other Pages and Controls
Remember that page and control compilation happens on a per-directory basis! So referencing other pages and controls becomes a little trickier in ASP.NET 2.0, because you cannot assume that a CodeBeside class from another page or control is available in the current assembly. At best, all pages and controls in the same directory end up in the same assembly; at worst, each page or control gets its own assembly and they know nothing about each other.

If you need to reference another page from a control or another page entirely, you need to explicitly import it with the @Reference directive. In ASP.NET 1.1, all CodeBehind classes are immediately available to your entire Web application. In ASP.NET 2.0, you must explicitly reference an assembly to load it.

Assume for a minute that you have the DataEntry.aspx page shown earlier and you want to create a second page that uses the same CodeBeside class so you can reuse the page logic, but change the page layout. So you create DataEntry2.aspx by changing a few colors and moving around the page controls. In essence, you want to have two ASPX pages reference the same CodeBeside file. Here's how to do this:

   <%@ Reference Page="~/DataEntry.aspx" %>
   <%@ Page Language="C#" AutoEventWireup="true" 
      Inherits="DataEntry" %>
I'm leaving out the CodeFile attribute reference and the CodeBeside class of the DataEntry page, and adding the @Reference tag to the page to force the CodeBeside class to import.

The same is true with any user control definitions. To import a user control you need to use the @Register tag, which imports the assembly that the control lives in. ASP.NET is smart during compilation and figures out exactly where related assemblies live based on how the project compiles. If the control or page resides in the same assembly, ASP.NET does not actually add a reference. But if the user control is external—in another directory, for example—then ASP.NET adds the assembly reference.

Referencing Problems
If you can explicitly reference other pages and controls in your markup pages, things work fairly well, but if you load controls or reference pages dynamically in your code, things get a lot more complicated. The most common problem I run into in ASP.NET 2.0 is loading controls dynamically.

In ASP.NET 1.x, you might have run code like this to dynamically load controls into a page.

   public partial class DynamicControlLoading : 
      protected CustomUserControl MessageDisplay;
      protected void Page_Load(object sender,
         EventArgs e)
         MessageDisplay = this.LoadControl(
            as CustomUserControl;
      protected void btnSay_Click(object sender, 
         EventArgs e)
In this case, CustomUserControl is a simple user control that lives in another directory and gets loaded dynamically at run time. Let's also assume that if you dynamically load this control you'll have a choice of several controls, or the end-user might even create a custom control that is dropped into place instead.

If you run the code above in ASP.NET 2.0, it will likely fail. I say likely because there are some inconsistencies that will sometimes pick up control references automatically. For example, this will happen if the user control lives in the same directory and compiles into the same assembly as the page, or if another page has the control referenced. But it should—and usually will—fail. Why? Because ASP.NET compiles on a directory level and the CustomUserControl lives in a separate directory and goes into a separate assembly. It's not visible for the page class to get a strongly-typed reference. IntelliSense will show a big, red exclamation point or nothing at all for the MessageDisplay control at design time, and when you run the page it will bomb.

You can reference the control generically as a Control type of course, but if you need to access any custom properties on the user control beyond Control properties, you have to resort to using reflection. As far as I know, there's no way to add a reference to another user control or page programmatically at run time.

As an alternative, you can choose to not load controls dynamically or at least provide a mechanism to load user controls beforehand on a page with the appropriate @Register tags. But that's not always possible. Another option is to create a user control base class in APP_CODE and expose the public interface there. The main problem with this is that this base class can't see the page's controls unless you use FindControl(), making this method cumbersome and ugly.

I've run into similar situations with inheritance scenarios, such as inheriting one master page off another's CodeBeside class. There are cases where inherited controls are not recognized properly by the higher level classes, resulting in type mismatches, especially when loading UserControls on master pages. Removing controls on inherited pages will also cause problems, even if the controls are defined explicitly in lower-level classes.

Inconsistencies that reference other types are incredible time wasters because you think that you have things working consistently only to find out later that's not so when you change a completely different page. What's worse is that you must understand the model in order to get your head around the problem.

The overall ASP.NET 2.0 compilation model is internally complex. Most of the time you don't need to understand it, but when you run into these boundary scenarios, you really must understand what goes on behind the scenes so you can work around the quirks.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date