AJAX and ASP.NET Template Controls

I was programming today (err. early morning, 1:00 AM) and stumbled across this error:

[NullReferenceException: Object reference not set to an instance of an object.]

   AjaxControlToolkit.ExtenderControlBase.LoadClientStateValues() in d:\E\AjaxTk-AjaxControlToolkit\Release\AjaxControlToolkit\ExtenderBase\ExtenderControlBase.cs:332

   AjaxControlToolkit.ExtenderControlBase.Page_PreLoad(Object sender, EventArgs e) in d:\E\AjaxTk-AjaxControlToolkit\Release\AjaxControlToolkit\ExtenderBase\ExtenderControlBase.cs:287

   System.EventHandler.Invoke(Object sender, EventArgs e) +0

   System.Web.UI.Page.OnPreLoad(EventArgs e) +86

   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +948

AJAX apparently blew chunks.  After taking a look at the AJAX source code ExtenderControlBase.cs (thank goodness it's open source), the LoadClientStateValues() was trying to load some hidden client state data stored in a hidden control being resolved by FindControl() method on NamingContainer.  Well, because I was using my AJAX control in a LayoutTemplate, NamingContainer tuned out to be null which was causing ASP.NET's OnPagePreload -> LoadClientStateValues() to fail.

Here was the offending code:

<asp:Login ID="Login2" runat="server" OnLoginError="Login2_LoginError">

    <LayoutTemplate>

            <fieldset>

                <div class="panel-username">

                    <p>

                        <asp:Label ID="UserNameLabel" runat="server" AssociatedControlID="UserName" CssClass="labeltext bold">Email Address:</asp:Label>

                        <asp:TextBox ID="UserName" runat="server" CssClass="textbox"></asp:TextBox>

                        <ajax:TextBoxWatermarkExtender ID="TextBoxWatermarkExtender1" runat="server" TargetControlID="UserName"

                            WatermarkText="Enter Email Address" WatermarkCssClass="watermark">

                        </ajax:TextBoxWatermarkExtender>

                        <asp:RequiredFieldValidator ID="UserNameRequired" runat="server" ControlToValidate="UserName"

                            ErrorMessage="User Name is required." ToolTip="User Name is required." ValidationGroup="ctl00$Login2">*</asp:RequiredFieldValidator>

                    </p>

                </div>

                <div class="panel-password">

                    <p>

                        <asp:Label ID="PasswordLabel" runat="server" AssociatedControlID="Password" CssClass="labeltext bold">Password:</asp:Label>

                        <asp:TextBox ID="Password" runat="server" TextMode="Password" CssClass="textbox"></asp:TextBox>

                        <asp:RequiredFieldValidator ID="PasswordRequired" runat="server" ControlToValidate="Password"

                            ErrorMessage="Password is required." ToolTip="Password is required." ValidationGroup="ctl00$Login2">*</asp:RequiredFieldValidator>

                    </p>

                </div>

                <div style="float: left; width: 150px;">

                    <p>

                        <span class="bold">Don't have an account?</span> <a id="A1" href="~/common/SignUp.aspx"

                            runat="server">Register here</a>. It's easy and free!</p>

                </div>

                <div class="panel-button">

                    <p>

                        <asp:ImageButton ID="LoginButton" runat="server" CommandName="Login" ValidationGroup="ctl00$Login2"

                            ImageUrl="~/Images/TransparentPixel.gif" CssClass="cmdSignIn" />

                    </p>

                    <p style="padding-top: 10px;">

                        <a href="#">Forgot password?</a></p>

                </div>

            </fieldset>

    </LayoutTemplate>

</asp:Login>

As you can see, the offending line of code is marked in bold above.  I was using the TextBoxWatermarkExtender on the UserName TextBox control.  Since AJAX needs a NamingContainer, a simple work around is to simply wrap the code in a ASP.NET Panel control, and you're problems will go away like so:

<asp:Login ID="Login2" runat="server" OnLoginError="Login2_LoginError">

                    <LayoutTemplate>

                        <asp:Panel ID="panWrapper" runat="server">

                            <fieldset>

                                <div class="panel-username">

                                    <p>

                                        <asp:Label ID="UserNameLabel" runat="server" AssociatedControlID="UserName" CssClass="labeltext bold">Email Address:</asp:Label>

                                        <asp:TextBox ID="UserName" runat="server" CssClass="textbox"></asp:TextBox>

                                        <ajax:TextBoxWatermarkExtender ID="TextBoxWatermarkExtender1" runat="server" TargetControlID="UserName"

                                            WatermarkText="Enter Email Address" WatermarkCssClass="watermark">

                                        </ajax:TextBoxWatermarkExtender>

                                        <asp:RequiredFieldValidator ID="UserNameRequired" runat="server" ControlToValidate="UserName"

                                            ErrorMessage="User Name is required." ToolTip="User Name is required." ValidationGroup="ctl00$Login2">*</asp:RequiredFieldValidator>

                                    </p>

                                </div>

                                <div class="panel-password">

                                    <p>

                                        <asp:Label ID="PasswordLabel" runat="server" AssociatedControlID="Password" CssClass="labeltext bold">Password:</asp:Label>

                                        <asp:TextBox ID="Password" runat="server" TextMode="Password" CssClass="textbox"></asp:TextBox>

                                        <asp:RequiredFieldValidator ID="PasswordRequired" runat="server" ControlToValidate="Password"

                                            ErrorMessage="Password is required." ToolTip="Password is required." ValidationGroup="ctl00$Login2">*</asp:RequiredFieldValidator>

                                    </p>

                                </div>

                                <div style="float: left; width: 150px;">

                                    <p>

                                        <span class="bold">Don't have an account?</span> <a id="A1" href="~/common/SignUp.aspx"

                                            runat="server">Register here</a>. It's easy and free!</p>

                                </div>

                                <div class="panel-button">

                                    <p>

                                        <asp:ImageButton ID="LoginButton" runat="server" CommandName="Login" ValidationGroup="ctl00$Login2"

                                            ImageUrl="~/Images/TransparentPixel.gif" CssClass="cmdSignIn" />

                                    </p>

                                    <p style="padding-top: 10px;">

                                        <a href="#">Forgot password?</a></p>

                                </div>

                            </fieldset>

                        </asp:Panel>

                    </LayoutTemplate>

                </asp:Login>

Now it works :)  Hope that helped anyone running into the same problem.  Whenever you're dealing with ASP.NET template controls, and you're using AJAX within these template controls, be sure to wrap the control pointed to by TargetControlId & the AJAX control itself in it's own naming container to avoid issues like this.  Another bug down fighting0028.gif. :)

2 Comments Filed Under [ Tips & Tricks Errors ]

Comments

# re: AJAX and ASP.NET Template Controls
Gravatar Nice hint that saved me a lotta work! Thx...
Left by Spock on 3/5/2008 4:41 AM
# re: AJAX and ASP.NET Template Controls
Gravatar Thanks a lot! I was having the exact same issue...!
Left by Zed on 10/30/2009 2:29 PM

Leave Your Comment

Title*
Name*
Email (never displayed)
 (will show your gravatar)
Url
Comment*

Please add 5 and 8 and type the answer here:

Preview Your Comment.