DCSIMG
ASP.NET 2.0 CodeBehind - Doron's .NET Space

ASP.NET 2.0 CodeBehind

I've always found the new CodeBehind model of ASP.NET 2.0 to be a bit confusing. What I like to do with confusing things that I want to remember and understand better, is to write them down. Here we go.

Of the top of your head, which classes will be generated by ASP.NET for the following WebForm?

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Tester.aspx.cs" Inherits="Tester" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Untitled Page</title> </head> <body> <form id="form1" runat="server"> <div> <asp:Button ID="Button1" runat="server" Text="Button" /></div> </form> </body> </html>

And the sophisticated code file...

public partial class Tester : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{

}
}

Looking at the temporary ASP.NET files directory, you will see 3 files:

1. App_Web_[GeneratedAssemblyName].1.cs will contain your code file definitions, meaning this:

//[Some using statements here] public partial class Tester : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{

}
}


#line default #line hidden

2. App_Web_[GeneratedAssemblyName].0.cs will contain two classes. The first one is the second part of your partial class:

public partial class Tester : System.Web.SessionState.IRequiresSessionState {


protected global::System.Web.UI.WebControls.Button Button1;

protected global::System.Web.UI.HtmlControls.HtmlForm form1;

protected System.Web.Profile.DefaultProfile Profile {
get {
return ((System.Web.Profile.DefaultProfile)(this.Context.Profile));
}
}
protected System.Web.HttpApplication ApplicationInstance {
get {
return ((System.Web.HttpApplication)(this.Context.ApplicationInstance));
}
}
}

So this class contains all the control definitions, and some helper properties which give you easy access to the Profile and Application objects. This is why you can access your page controls programmatically without defining them in your code file (as in ASP.NET 1.1): They're in the second part of your class, which is generated behind the scenes by ASP.NET.

But that's not where all the actions is at, this file contains one more class (I've left only a small part of the code for this class, to focus on what's interesting for us):

1 [System.Runtime.CompilerServices.CompilerGlobalScopeAttribute()]
2 public class tester_aspx : global::Tester, System.Web.IHttpHandler {
3
4 private void @__BuildControlTree(tester_aspx @__ctrl) {
5
6 this.InitializeCulture();
7 //Lots of page parsing code deleted here 8 global::System.Web.UI.HtmlControls.HtmlForm @__ctrl2;
9 @__ctrl2 = this.@__BuildControlform1();
10 @__parser.AddParsedSubObject(@__ctrl2);
11 @__parser.AddParsedSubObject(new System.Web.UI.LiteralControl("\r\n</body>\r\n</html>\r\n"));
12 }
13
14 protected override void FrameworkInitialize() {
15 base.FrameworkInitialize();
16 this.@__BuildControlTree(this);
17 this.AddWrappedFileDependencies(global::ASP.tester_aspx.@__fileDependencies);
18 this.Request.ValidateInput();
19 }
20
21 public override void ProcessRequest(System.Web.HttpContext context) {
22 base.ProcessRequest(context);
23 }
24 }

This is the actual class that is instantiated by ASP.NET on every request. As you can see, this class inherits our Tester page, and is generated from the aspx file we created above. It all starts with the ProcessRequest method, whose base implementation will call the FramworkInitialize along the way. There the control tree of the page will get built. Check out line 11: you can see how all the 'free roaming strings' we have in our aspx file are wrapped with LiteralControls.

To summarize, for every WebForm we create ASP.NET generates for us one brother and one son. The brother is a helper that contains useful control definitions and other properties. The son is generated from the aspx file and is responsible for the page parsing and control-tree building.

But wait a second, I said 3 files, didn't I? I almost forgot this one:

3. App_Web_[GeneratedAssemblyName].2.cs:

namespace @__ASP {
internal class FastObjectFactory_app_web_kfeaunlh {

private FastObjectFactory_app_web_kfeaunlh() {
}

static object Create_ASP_tester_aspx() {
return new ASP.tester_aspx();
}
}
}

Well, actually this class is not generated for every Page we have. We'll get one of those per assembly, which usually means per directory in ASP.NET 2.0 (since by default every directory in our web site will be compiled into a single assembly). If we add another form and a user control to our directory it will look like this:

internal class FastObjectFactory_app_web_bkne5flo {

private FastObjectFactory_app_web_bkne5flo() {
}
static object Create_ASP_webusercontrol_ascx() {
return new ASP.webusercontrol_ascx();
}

static object Create_ASP_tester2_aspx() {
return new ASP.tester2_aspx();
}

static object Create_ASP_tester_aspx() {
return new ASP.tester_aspx();
}
}

As it name suggests, the purpose of this class is to quickly instantiate our forms and user-controls. Apparently, this is a kind of trick that allows the instantiation of the types by reflection to be faster. You can read more about it in Fritz Onion's post.

Writing all this down really helped to set things straight in my head - hopefully you'll find it useful as well. In a sequel for this post, I intend to write about another confusing (and very related) subject - the ASP.NET 2.0 compilation model. Stay tuned.

Published Friday, February 23, 2007 9:02 AM by dorony
תגים:

Comments

No Comments

Leave a Comment

(required) 
(required) 
(optional)
(required) 

Enter the numbers above: