通过存储过程与ControlParameter传用户至GridView时遇控件查找错误
错误信息
服务器错误 '/' 应用程序。
找不到ControlParameter 'httpuser'中的控件 'hdn_httpuser'。
描述: 执行当前Web请求期间发生未处理的异常。请查看堆栈跟踪以获取有关错误及其代码来源的更多信息。异常详细信息: System.InvalidOperationException: 找不到ControlParameter 'httpuser'中的控件 'hdn_httpuser'。
源错误:
执行当前Web请求期间生成了未处理的异常。可通过下面的堆栈跟踪信息确定异常的起源和位置。
堆栈跟踪:
[InvalidOperationException: 找不到ControlParameter 'httpuser'中的控件 'hdn_httpuser'。]
System.Web.UI.WebControls.ControlParameter.Evaluate(HttpContext context, Control control) +553
System.Web.UI.WebControls.Parameter.UpdateValue(HttpContext context, Control control) +70
System.Web.UI.WebControls.ParameterCollection.UpdateValues(HttpContext context, Control control) +137
System.Web.UI.WebControls.SqlDataSource.LoadCompleteEventHandler(Object sender, EventArgs e) +59
System.EventHandler.Invoke(Object sender, EventArgs e) +0
System.Web.UI.Page.OnLoadComplete(EventArgs e) +138
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +5909
现有代码
后台代码(aspx.cs)
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; namespace WorldsStrongestProgrammer2024App { public partial class Orientation : System.Web.UI.Page { // 继承自母版页 // # 用户检查变量 public Orientation() { } public string httpuser; public string GetHttpUser() { var a = HttpContext.Current.User.Identity.Name.ToString(); httpuser = a; return httpuser; } protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { GetHttpUser(); } if (HttpContext.Current.User.Identity.IsAuthenticated) { GetHttpUser(); } } } }
前端页面(aspx)
<asp:GridView runat="server" ID="gv_httpuser"> <columns> <asp:TemplateField> <ItemTemplate> <asp:TextBox ID="hdn_httpuser" runat="server" Value="<%: httpuser %>"/> </ItemTemplate> </asp:TemplateField> </columns> </asp:GridView> <asp:GridView runat="server" ID="gv_aspuser" DataSourceID="sql_aspuser" AutoGenerateColumns="true" DataKeyNames="HttpUser"> </asp:GridView> <asp:SqlDataSource runat="server" ID="sql_aspuser" ConnectionString="<%$ ConnectionStrings:Documents_SQLConn %>" SelectCommand="sLoginWizardOrientation_Step1" SelectCommandType="StoredProcedure"> <SelectParameters> <asp:ControlParameter controlID="hdn_httpuser" PropertyName="Text" Name="httpuser" Type="String" /> </SelectParameters> </asp:SqlDataSource>
SQL存储过程
CREATE PROCEDURE sLoginWizardOrientation_Step1 (@httpuser varchar(max) = '%') AS SELECT [Id], [Hometown], [Email], [PhoneNumber], [UserName] AS HttpUser FROM [db_a84118_maindocuments].[dbo].[AspNetUsers] WHERE UserName = @httpuser
问题根源
hdn_httpuser被放在gv_httpuser的ItemTemplate中,而这个GridView没有绑定任何数据,页面渲染时不会生成这个TextBox控件。- 即使GridView有数据,模板内的控件属于GridView的子容器,SqlDataSource在页面生命周期的
LoadComplete阶段查找控件时,无法直接通过ID定位到子容器内的控件(会生成带GridView前缀的客户端ID)。 - 用TextBox存储隐藏值不合理,应该用专门的
HiddenField控件。
解决方案
方案一:改用页面级HiddenField
修改后台代码
using System; using System.Web.UI; using System.Web.UI.WebControls; namespace WorldsStrongestProgrammer2024App { public partial class Orientation : Page { protected void Page_Load(object sender, EventArgs e) { if (HttpContext.Current.User.Identity.IsAuthenticated) { // 直接给HiddenField赋值当前用户名 hdn_httpuser.Value = HttpContext.Current.User.Identity.Name; // 手动触发GridView绑定确保数据加载 gv_aspuser.DataBind(); } } } }
修改前端页面
<!-- 用HiddenField替代GridView内的TextBox --> <asp:HiddenField runat="server" ID="hdn_httpuser" /> <asp:GridView runat="server" ID="gv_aspuser" DataSourceID="sql_aspuser" AutoGenerateColumns="true" DataKeyNames="HttpUser"> </asp:GridView> <asp:SqlDataSource runat="server" ID="sql_aspuser" ConnectionString="<%$ ConnectionStrings:Documents_SQLConn %>" SelectCommand="sLoginWizardOrientation_Step1" SelectCommandType="StoredProcedure"> <SelectParameters> <!-- 指向HiddenField的Value属性 --> <asp:ControlParameter ControlID="hdn_httpuser" PropertyName="Value" Name="httpuser" Type="String" /> </SelectParameters> </asp:SqlDataSource>
方案二:直接在代码中给SqlDataSource赋值参数(更简洁)
这种方式不需要额外的隐藏控件,直接通过代码传递参数:
修改后台代码
using System; using System.Web.UI; using System.Web.UI.WebControls; namespace WorldsStrongestProgrammer2024App { public partial class Orientation : Page { protected void Page_Load(object sender, EventArgs e) { if (HttpContext.Current.User.Identity.IsAuthenticated) { // 直接给SqlDataSource的参数赋值 sql_aspuser.SelectParameters["httpuser"].DefaultValue = HttpContext.Current.User.Identity.Name; gv_aspuser.DataBind(); } } } }
修改前端页面
<asp:GridView runat="server" ID="gv_aspuser" DataSourceID="sql_aspuser" AutoGenerateColumns="true" DataKeyNames="HttpUser"> </asp:GridView> <asp:SqlDataSource runat="server" ID="sql_aspuser" ConnectionString="<%$ ConnectionStrings:Documents_SQLConn %>" SelectCommand="sLoginWizardOrientation_Step1" SelectCommandType="StoredProcedure"> <SelectParameters> <!-- 仅定义参数,不依赖控件 --> <asp:Parameter Name="httpuser" Type="String" /> </SelectParameters> </asp:SqlDataSource>
额外优化建议
- 移除原代码中无用的
GetHttpUser方法和httpuser字段,直接在需要的地方获取HttpContext.Current.User.Identity.Name即可。 - 可以在Page_Load中添加判断,如果用户未认证,直接跳转到登录页,避免后续逻辑出错。
内容的提问来源于stack exchange,提问作者PJ Martin

