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>
<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>
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 .
:)
Comments
Spock
Nice hint that saved me a lotta work! Thx…
Zed
Thanks a lot! I was having the exact same issue…!
Leave a comment
Your email address will not be published. Required fields are marked *