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";

    Controls.Add(products);       

}

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.

c:\dev\WebSites\WebSite9\Default2.aspx.cs(16):
error CS0246: The type or namespace name 'Products' could not be found (are you missing a using directive or an assembly reference?)

Ouch.

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.


Comments
Thomas Eyde Thursday, June 30, 2005
I think you just gave me a glimps of the future. Like CruiceControl has already ditched Web Forms, I think other projects will ditch other things in ASP.NET, in the end leaving nothing but the engine.

If multiple folders is bad, we will avoid them. If multiple web forms is bad, we will avoid them, too. Or leave just one as the front controller.

We will use VS for it's intellisense. If we dig static typing and/or generics, then we stick with C#.

But I really can't see why we all wouldn't jump on the RoR band wagon.
Rick Strahl Wednesday, July 6, 2005
Scott,

Microsoft has gotten a lot of flak over the inability to access other pages and user controls and it looks like they are once again changing the way this works (according to a response I got on the Whidbey forums). The Microsoft person wasn't specific, but it sounds like code behind files will end up in App_Code, and then become part of the main assembly, to which you can cast.

Has anybody checked out June CTP to see if this has been implemented?
scott Wednesday, July 6, 2005
Interesting, Rick. I'll have to give the June CTP a quick look this weekend to see what it is doing now...
Ben Sunday, October 23, 2005
Sorry if I'm coming into this missing everything but why do I want to add
-fixednames? why would I want every webform to be a seperate assembly?
scott Monday, October 24, 2005
I think -fixednames is the safe option because it can expose where I might be missing an @ Reference. It's just like compiling with all warning turned on. I wouldn't want to deploy all those assemblies, just build that way to test.
Nitin Wednesday, January 4, 2006
Hi Scott,
Here is one line from your article
"The pre-compiled code will end up inside of the Temporary ASP.NET File directory, just as it would when the runtime compiles files for a browser request. Inside of the bin directory for the compiled site, you’ll find the assemblies (dll files)."

I precompiled the site with this command
aspnet_compiler -v /website1
It generated precompiled code in Temporary ASP.Net folder but it didn't created any bin folder as u mentioned(it does that when i precompile for Deployment)

There is one more strange behaviour i observed.
When i requested the default.aspx for the first time then it created one child node bin inside website1 (it is not directly visible in IIS console but if u acess it programatically using DirectoryServices like this

de = new DirectoryEntry("IIS://localhost/W3SVC/1/Root/WebSite1/bin");
PropertyValueCollection pvc = de.Properties["Path"];
Response.Write(pvc.Value);
It didn't returned any physical path but it exists.
So whats the significance of this?
Comments are now closed.
by K. Scott Allen K.Scott Allen
My Pluralsight Courses
The Podcast!