OdeToCode IC Logo

One More On ASP.NET 2.0 Compilation

Thursday, June 30, 2005

I’m trying to move past the subject of ASP.NET 2.0 compilation to something new, really I am, but between some insightful questions I’ve seen, and work on my own code, I’m starting to have … issues.

Switching Pre-compilation Models Can Expose Broken Code

Let’s say you have a web form and need to dynamically load a user control. The code inside a web form might look like:


    Products products;

    products = LoadControl("Products.ascx") as Products;

    products.CategoryName = "Blunt Instruments";



We can build the code from the IDE with no errors. We can do a simple precompilation from the command line with no errors. There are errors, however, if we add –fixednames during precompilation.

C:\Documents and Settings\bitmask>aspnet_compiler -p "c:\dev\WebSites\WebSite9" -f -v / -fixednames c:\temp\website1
Utility to precompile an ASP.NET application
Copyright (C) Microsoft Corporation. All rights reserved.

error CS0246: The type or namespace name 'Products' could not be found (are you missing a using directive or an assembly reference?)


When building from the IDE, the runtime was batch compiling all the aspx and ascx files inside the root directory into a single assembly. With –fixednames each aspx and ascx compiles into a separate assembly. The precompiler doesn’t know where the Products type lives now - there is no reference.

What we should have done from the start was use an @ Reference in the ASPX like so:

<%@ Reference VirtualPath="~/Products.ascx"  %>

The point isn’t how to make things work, the point is we wouldn’t have these idiosyncrasies if the compilation model was simple instead of complicated.

We Don’t Need No Stinkin’ Projects

The first hint of trouble should have come when typing in the code to interact with the user control. There is no Intellisense. Why? Because there is no real "project" for a web project. Pick one of the following perspectives on this fact:

One way to view the 'project-less' project is to picture each webform as an island – an autonomous service whose type is unknown outside it’s own declaration. Each web form can end up in a distinct assembly. No one webform knows anything about any other webform. This perspective is pleasant.

A second, less flattering view of the 'project-less' project is how a web application is no longer a cohesive unit, but a random collection of whatever known files the IDE can find inside your folders. Point the IDE to a folder, throw anything in, it will compile when the time comes. It feels sloppy.

If you do need to share secrets between webforms, you need to use the aforementioned @ Reference directive. For example, when someone needs to pass values between web forms, they often find the following article on MSDN: Passing Server Control Values Between Pages. I’ve never liked this approach – it has the aroma of an anti-pattern. The approach will also not compile in ASP.NET 2.0 unless you @ Reference the first web form with a Virtual Path from the second (transfer target) web form.

There is at least one other migration scenario where this can sting. Let’s say you have stand alone .cs or .vb file in a 1.x web project. From within the class you use a second class that is a code-behind class for a webform. I don’t advocate this approach, but I can understand some scenarios where it would be useful.

The 2.0 migration wizard will move the stand alone source file into the /App_Code directory, and the code will compile into the App_Code assembly. Types inside the App_Code assembly will have no knowledge of any code behind classes - you cannot get to them. There is no easy way to get this scenario to work in Beta 2 without injecting an abstract base class for your webform code-behind class into /App_Code.

To solve this, the ASP.NET team decided to automatically generate stub classes for code-behind classes into the App_Code directory in post-Beta 2 builds.

I feel like I’m studying a Rube Goldberg machine.