It Could Be Done!

the blog about ASP.NET and not only

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. 

Posted: Oct 09 2007, 04:49 PM by ysw | with 24 comment(s) |
Filed under:

Comments

Emil Stoychev said:

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?

# October 9, 2007 10:22 AM

ysw said:

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

# October 9, 2007 10:32 AM

Emil Stoychev said:

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

# October 9, 2007 10:50 AM

Joe Chung said:

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.

# October 9, 2007 11:23 AM

ysw said:

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.  

# October 9, 2007 11:30 AM

AndrewSeven said:

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!";

   }

# October 9, 2007 12:41 PM

ysw said:

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.

# October 9, 2007 4:55 PM

bschooley said:

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

# October 9, 2007 5:08 PM

Kylir Horton said:

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.

# December 21, 2007 9:48 AM

imiv said:

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

# February 27, 2008 9:43 AM

ysw said:

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.

# February 27, 2008 10:25 AM

NH said:

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.

# April 14, 2008 1:58 PM

NH said:

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).

# April 15, 2008 11:42 AM

Name said:

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:

# November 3, 2010 4:55 PM

photo printer reviews said:

ohhh great information

--------------------------------------------------------------------    

African Studies

# January 17, 2011 4:54 PM

product reviews said:

"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."

# February 11, 2011 8:20 AM

weblogs.asp.net said:

Master page and preinit.. Super :)

# March 28, 2011 4:09 PM

Norman said:

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!

# April 15, 2011 3:24 PM

weblogs.asp.net said:

Master page and preinit.. Awful :)

# June 8, 2011 8:42 PM

Kevin said:

@Name

It works in my project. :P

# June 14, 2011 3:14 PM

Vikram Singh Saini said:

Solution is extremely nice.

I would like to know reason why this lines work.

# March 24, 2012 11:17 AM

Ahmed said:

Thanks, it helps a lot.

# April 5, 2012 7:05 AM

Shlomit said:

thanks a lot! brilliant and helpfull solution

# August 27, 2012 4:38 AM

Piyush said:

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.

# October 18, 2012 10:28 PM