0
votes

I am thinking about the asp.net 2.0 code behind model.

After I drag a button onto my Default.aspx page, I got the following declaration in my Default.aspx.designer.cs file:

public partial class _Default {

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

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

And now it's OK for me to write the following code in Default.aspx.cs file:

protected void Button1_Click(object sender, EventArgs e)
{
    Button1.Text = "clicked!";
}

But I am wondering, what I got is nothing but a declaration of Button1 variable of Button type, it hasn't been instanciated, how could this code run without trigging a Null Reference Exception?

I think there must exist some code like this somewhere:

Button1 = new Button();

But where is this code? When is this code executed? Who executes it?

Many thanks...

Update - 1 - 21:17 12/15/2010

I found 2 auto-generated file in a mysterious location C:\Windows\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\root\edd9f4a1\7f113408, they are:

App_Web_x_swwj6s.1.cs
App_Web_x_swwj6s.0.cs

I found code like below in the App_Web_x_swwj6s.0.cs file:

        private global::System.Web.UI.WebControls.Button @__BuildControlButton1()
         {
            global::System.Web.UI.WebControls.Button @__ctrl;                
            @__ctrl = new global::System.Web.UI.WebControls.Button();
            //....
            this.Button1 = @__ctrl;
            return @__ctrl;
          }

And this method is invoked in the below code:

private global::System.Web.UI.HtmlControls.HtmlForm @__BuildControlform1()
{
  //....
  global::System.Web.UI.WebControls.Button @__ctrl1;

  @__ctrl1 = this.@__BuildControlButton1();
  //......
}

And finally the above code is invoked in the following method:

protected override void FrameworkInitialize()

So I believed that the FrameworkInitialize() method is the one who did the dirty job of bind the control reference to a control instance.

To prove this, I intentionally wrote the following code in my code-behind file:

protected override void FrameworkInitialize()
{
    this.Button1 = null;
}

I hope there would be a Null Reference Exception when I click the button, but strange enough, the whole web site run smoothly.

Is it true that all the controls I declared in the aspx file are created with the FrameworkInitialize() method? Why there's no Null Reference Exception in the above scenario?

Many thanks again.

Update - 2 - 21:43 12/15/2010

I think I may find the explanation, I checked the final page class generated by ASP.NET with .NET reflector. Its deriving relation is like this:

default_aspx class (The ultimate class representing the page)<--- _Default class (the code behind class) <--- System.Web.UI.Page

And in the default_aspx class, I found this:

protected override void FrameworkInitialize()
{
    base.FrameworkInitialize();  // Button1=null is executed here.
    this.__BuildControlTree(this); // Here Button1 is STILL set to an instance.
    base.AddWrappedFileDependencies(__fileDependencies);
    base.Request.ValidateInput();
}

So, this could explain why my intention to set the Button1 to null failed.

Now, my question is, does the FrameworkInitialize() method has to be called at the very beginning of a page's life cycle so that we could use the control on the page afterwards.

Update - 3 - 3:45 PM 12/16/2010

From here:

Once the HTTP page handler class is fully identified, the ASP.NET run time calls the handler's ProcessRequest method to process the request. Normally, there is no need to change the implementation of the method as it is provided by the Page class.

This implementation begins by calling the method FrameworkInitialize, which builds the controls tree for the page. The method is a protected and virtual member of the TemplateControl class—the class from which Page itself derives. Any dynamically generated handler for an .aspx resource overrides FrameworkInitialize. In this method, the whole control tree for the page is built.

A bounty is started for your precious comments. :)

2
Since the "answer" was deleted but I think the link within it might still have relevant information to someone viewing this question: peterkellner.net/2006/07/12/…Joel Etherton

2 Answers

3
votes

So what exactly do you want to get answers to now... to me it looks like you're answering most of your questions your self? :)

Regarding the FrameworkInitialize its easiest if you fire up Reflector and look at the code. Code is law! :) In here you'll see that System.Web.UI.TemplateControl.FrameworkInitialize() will call a internal method named System.Web.Compilation.BuildResultNoCompileTemplateControlFrameworkInitialize(TemplateControl)which is doing the actual initialization of your control tree. This means that overriding FrameworkInitialize() and setting your Button1 to null doesn't have any effect, since that code will end up being run BEFORE the control tree is initialized.

3
votes

The page and its controls (including your button in this case) are instantiated by the webforms "view engine" before the OnLoad, etc events are fired.

Otherwise, you'd have to have an ISAPI filter or similar device intercept requests and create the page object and its controls before any events were fired. This is what the ASP.NET ISAPI DLL does, I think.

I haven't tried this, but you may be able to set a break point in the page's constructor to see the ::Controls[] list before anything is created, which I would expect to be empty (but the page life cycle link I've provided below will have a better explanation).

See this link or this one.