Thoughts, Tips and Tricks on what I'm currently do for a living. Currently most of my spare time is spent on contributing to Akka.NET.

Friday, July 27, 2007

AutoEventWireup=true

If you specify the attribute AutoEventWireup=True on a Web User Control or a Page, methods like Page_Init() och Page_Load() will be automatically routed to the page's Init- and Load-events.

This is good, sometimes. It simplifies for you since you don't have to hook up events to event handlers. But it is something that's done during runtime, and therefore adds to the executiion time and it may cause event handlers to be called many times.

Example: Event handler beeing called twice.

protected void Page_Init()
{
    Page.Load += Page_Load;
}
protected void Page_Load(object sender, EventArgs e)
{
    //This code will execute twice
}

Page_Load in the example above will be called twice. Once since you mannually hooked the event to the Page_Load handler. Another time since AutoEventWireup=true and the method has a name causing the event to automatically be hooked to it.

AutoEventWireup works on TemplateControl which both Page och Web User Controls derives from.

K Scott Allen's blog talkes about this. I'll go more into depths.

SupportAutoEvents

What happens when AutoEventWireup=true? A TemplateControl has a property SupportAutoEvents. This is true by default (and will change to false by the parser/control builderif you set the attribute AutoEventWireup=false).

HookUpAutomaticHandlers

TemplateControl.HookUpAutomaticHandlers (which is called during the OnInit) will, if AutoEventWireup=true try to find methods with these names:

  • If the control is a Page:
    • Page_PreInit
    • Page_PreLoad
    • Page_LoadComplete
    • Page_PreRenderComplete
    • Page_InitComplete
    • Page_SaveStateComplete
  • For all TemplateControls:
    • Page_Init
    • Page_Load
    • Page_DataBind
    • Page_PreRender
    • Page_Unload
    • Page_Error
    • Page_AbortTransaction  or if it does not exist; OnTransactionAbort
    • Page_CommitTransaction  or if it does not exist; OnTransactionCommit

This is carried out in TemplateControl.GetDelegateInformationWithNoAssert().

32 attempts

As K Scott Allen writes two attempts will be made for every name. First it will try to find an EventHandler with the specified name, i.e. a method with the signature:

void EventHandler(object sender, EventArgs e)

Exemple: A method that is an EventHandler

void Page_PreInit(object sender, EventArgs e)

If that fails a VoidMethod is searched for, i.e. a method with the signature:

void VoidMethod()

Exemple: A method that is a VoidMethod

void Page_PreInit()

Although no methods matching the list have been added to the Page, 32 attempts to find a method will be made (K Scott Allen got 28 but he must have forgotten about OnTransactionAbort and OnTransactionCount).

Ok, the result will be cached but the search will be made at least once, at that's for every TemplateControl.

Hook up the event to the handler

For all matching methods on the control TemplateControl.HookUpAutomaticHandlers() will hook up the event to the corresponding event handler, unless the method already has been added to the event since HookUpAutomaticHandlers searches the list of event handlers for the event. If it finds the method, it will not add the method again.

But wait. In the first example Page_Load() was obviously added twice to the event.
Yes, but that's because HookUpAutomaticHandlers already had hooked up the Page.Load event to the Page_Load handler when we in Page_Init did it. Remember that HookUpAutomaticHandlers is called in the Page's OnInit, which is called before our Page_Init method. If we hook up the event to the handler before the page's OnInit we will do it before the HookUpAutomaticHandlers has ben called and therefore Page_Load will only be called once.

Exemple: Page_Load is only called once.

public partial class _Default : System.Web.UI.Page
{
    public _Default()
    {
        Page.Load += Page_Load;
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        //This code will execute once
    }
}

Conclusion: AutoEventWireup=false

Consider setting AutoEventWireup=false and manually hook up the events to the handlers. You gain control over when things are called and you don't have to pay for the overhead TemplateControl.HookUpAutomaticHandlers causes.

Microsoft recommends setting it to false if performance is a key consideration.

More on AutoEventWireup on MSDN

http://msdn2.microsoft.com/en-us/library/system.web.configuration.pagessection.autoeventwireup.aspx
http://support.microsoft.com/default.aspx/kb/324151