Master Page and PreInit

Emil Stoichev reminded today that it is very important to understand what is ViewState, how it works and how we should use it.  The other problem mentioned there is unavailability of controls in PreInit phase if MasterPage is used. 

The problem is very simple.  If you have the following content page (in master page),

<%@ Page Language="C#" MasterPageFile="~/MasterPage.master" Title="Page" %>

<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
    <p>Content</p>
    <p><asp:Label runat="server" ID="ContentPageLabel" /></p>
</
asp:Content>

<
script runat="server">
    protected override void OnPreInit(EventArgs e)
    {
        base.OnPreInit(e);
        // next line crashes
        ContentPageLabel.Text = "Hello, World!";
    }
</script>

it crashes on the label text assignment with:

Object reference not set to an instance of an object.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.

Source Error:

Line 11: base.OnPreInit(e); 
Line 12: // next line crashes
Line 13: ContentPageLabel.Text = "Hello, World!";
Line 14: }
Line 15: </script>

I had to solve this problem some time ago,and  I found that once you access the Master property of you content page for the first time all controls become  instantiated.

So, adding just a single line of code before label text assignment fixes the problem.

<%@ Page Language="C#" MasterPageFile="~/MasterPage.master" Title="Untitled Page" %>

<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
    <p>Content</p>
    <p><asp:Label runat="server" ID="ContentPageLabel" /></p>
</
asp:Content>

<
script runat="server">
    protected override void OnPreInit(EventArgs e)
    {
        base.OnPreInit(e);
        // the following line is important
        MasterPage master = this.Master;
        // unfortunately, compiler warns us that master is not used

        ContentPageLabel.Text = "Hello, World!";
    }
</script>

Note that everything works like without MasterPage with this small change. 

24 Comments

  • I've just tested your workaround and it works, but honestly I can't understand why. It doesn't actually loads the MasterPage which was my first thought. Can you explain why this does work?

  • Page.Master property getter triggers creation of the master page and in turn master page instantiates ITemplates generated for each section. I remeber I was looking into the Temporary ASP.NET Files folder to find out how pages are wrapped into master page.

  • It looks like a cheap operation. I'll give it a try ;). Thanks.

  • You could avoid this cruft entirely by accessing the control in the Init event instead of PreInit. The PreInit event is a good place to do things like change master pages and themes in code, not access controls.

  • Joe, Emil suggested to use PreInit as this is the only way to set control properties before controls start tracking ViewState. This way, it is possible to get smaller ViewState without disabling it. So, if you DataBind your DropDowns in PreInit (depending on QueryString) you avoid placing their items in the ViewState.

  • Unless there has been a change, it is Init, not PreInit.

    I would guess that the property access triggers CreateChildControls().

    Things that happen late (Render) are not tracked by viewstate either.

    There must be a more elegant solution to this problem, but if nothing else, you could use the more explicit:

    protected override void OnLoad(EventArgs e)
    {
    base.OnLoad(e);
    ContentPageLabel.EnableViewState=false;
    ContentPageLabel.Text = "Hello, World!";
    }

  • Andrew, you are right, control does not trackview state at the time of Init event, but Page_Init fires the last one and at this time all controls already track viewstate. That is why at the page lavel, PreInit is important.

  • Just taking a guess here really, but did you try calling "EnsureChildControls()" during OnPreInit before setting the property?

  • Another good use of this is moving around AJAX controls within the page's control collection. They don't like to be moved after PreInit. That's what I'm using this trick for.

  • How avoid this problem if I use .Net 3.5? This solution does not work :-( Could you please help me?

  • What is the problem with .NET 3.5? As .NET 3.5 is .NET 2.0 SP1 + new assemblies I do not see a reason why something must be different.

  • Also finding that this does not work in .NET 3.5. However, one thing I've noticed is that if you type this.Master in the Immediate window of the IDE, it does have the desired effect. I guess the IDE invocation does a deeper prodding of the object.

  • It does work under 3.5 as well (note that 3.5 uses the same System.Web). The trick, in my case, was that 3.5 has better support for nested master pages: if you have a nested master, make sure to iterrate all the way to the root before you can access child controls on PreInit (e.g. this.Master.Master).

  • This is wrong, it should be done in Page_Load with if (!Ispostback). The control could not even have been initiated yet with Page_Init and you're talking about OnPreInit. This is so wrong D:

  • ohhh great information

    --------------------------------------------------------------------
    African Studies

  • "Hello, I found your web site in a new directory of blogs. I dont know how your blog arrived up, must happen to be a typo, Your web site seems beneficial. Have a nice day."

  • Master page and preinit.. Super :)

  • Excellent article! I was dynamically creating linkbuttons in the page_load and wonder why the oncommand wasn't firing after postback.I moved them to the preinit and now the oncommand fires, thanks!

  • Master page and preinit.. Awful :)

  • @Name

    It works in my project. :P

  • Solution is extremely nice.

    I would like to know reason why this lines work.

  • Thanks, it helps a lot.

  • thanks a lot! brilliant and helpfull solution

  • Excellent, I had dynamically added controls (TextBoxes, & Labels) in a normal web page before and the entire operation ran smoothly. However, the same logic was not working for the Web Pages with a Master Page.

    Thnx for the info.

Comments have been disabled for this content.