Friday, January 11, 2008

ASP.NET Auto Event Wiring

we promised to discuss Page Processing. Well, that'll be the next article, we promise (again). This one's focussed on explaining some behaviour we demonstrated but couldn't immediately explain to ourselves (not that we told you:-).

Please sir, why did the Page_Load method get called?
In the previous article, we remarked that the recommended location for event handling logic is the Web Form class (aka code behind class). In all-too-typical article fashion we then went and flagrantly broke the rule, putting a Page_Load method into the .aspx file in our example, just because it made our lives easier. Well, although it did make our lives easier, it also sparked our curiosity -- why'd it work?

If we take a look at the generic Web Form class produced by Visual Studio, we can see the code that enlists event handlers (in bold):

using ...;

public class WebForm : System.Web.UI.Page {
public WebForm() {
Page.Init += new System.EventHandler(Page_Init);
}

protected void Page_Load(object sender, EventArgs e) {
if (!IsPostBack) { }
}

protected void Page_Init(object sender, EventArgs e) {
InitializeComponent();
}

private void InitializeComponent() {
this.Load += new System.EventHandler(this.Page_Load);
}
}

So just how is it that a method we create in the .aspx file -- named Page_Load -- automatically handles the load event of the Web Form without any similar binding code?

As always, the answer lies in the internals of ASP.NET. And it's pretty simple. We just have to dig around a little to find it.


ASP.NET Internals - TemplateControl's HookUp
The answer lies in the System.Web.UI.TemplateControl class (which the System.Web.UI.Page class inherits from). It contains a HookUpAutomaticHandlers method that is responsible for associating all the control events (such as init, load, databind, ...) with event handling methods that follow the naming protocol "Page_" (such as "Page_Init", "Page_Load", etc.).

Well, to be just a little more precise, the HookUpAutomaticHandlers method only does the binding if you haven't set the undocumented (as at Beta1) @Page directive called AutoEventWireup to false. Beware of this little bit of trickery because Visual Studio does set this value to false when you ask it to add a Web Form into your project. And remember, when it's set to false, "no free event handlers for you!".

Since our example contained no such AutoEventWireup attribute, the TemplateControl class automatically bound our Page_Load method to the Web Form's load event and our Button was named "FooBar" just as we hoped. Lovely.

Just as an open-ended question, why does the TemplateControl class have Page-based wiring in it when it is also the base class of UserControl? This seems a rather bad breach of The Open Closed Principle (you have read that paper like we suggested, haven't you?).

No comments: