【问题标题】:Theme + dynamic control creation + Invisible UserControl = view state error?主题 + 动态控件创建 + 不可见的 UserControl = 视图状态错误?
【发布时间】:2017-04-13 21:51:30
【问题描述】:

default2.aspx

<%@ Page Language="C#" AutoEventWireup="true" Theme="Blue" %>

<%@ Register TagPrefix="uc1" TagName="favicon" Src="~/FavIcon.ascx" %>

<!DOCTYPE html>

<script runat="server">


    private void Page_PreRender(object sender, System.EventArgs e)
    {
        HtmlGenericControl scriptControl = new HtmlGenericControl("script");
        Page.Header.Controls.AddAt(0, scriptControl);//If this line is commented out, no exception will occur.
    }


    private void Page_Init(object sender, System.EventArgs e)
    {
        ScriptManager oSM = new ScriptManager();
        Page.Form.Controls.Add(oSM);//If this line is commented out, no exception will occur.
    }


</script>

<html>
<head runat="server">
    <title></title>
    <uc1:favicon runat="server"></uc1:favicon>
</head>
<body>
    <form id="form1" runat="server">
        <asp:Button ID="Button1" runat="server" Text="Button" />
    </form>
</body>
</html>

FavIcon.ascx

<%@ Control Language="C#" ClassName="FavIcon" AutoEventWireup="true" %>

<script runat="server">

    void Page_Load(object sender, EventArgs e)
    {
        this.Visible = false;//If this line is commented out, no exception will occur.
    }

</script>

还将样式表添加到蓝色主题。

页面打开成功,但是一旦我点击按钮,它就会抛出异常

加载视图状态失败。视图状态所在的控制树 正在加载的必须与用于保存的控制树匹配 上一个请求期间的视图状态。例如,当添加 动态控制,回发期间添加的控件必须匹配 在初始阶段添加的控件的类型和位置 请求。

谁能解释为什么会发生这个错误?

【问题讨论】:

  • 这是当您将视图状态(默认启用)与动态控件(controls.Addxxx)结合时遇到的经典错误:blogs.msdn.microsoft.com/asiatech/2011/10/25/…(theme=blue 动态添加控件,Visible=true 添加信息到视图状态等)。
  • @SimonMourier 只有当这三个因素存在时才会发生错误。你能解释一下为什么当我删除三个因素中的任何一个时错误不会发生吗?

标签: c# asp.net viewstate


【解决方案1】:

要调试这些错误,我强烈建议启用跟踪(@page 指令中的 Trace="true",或使用 global setting in web.config),以便查看服务器的控制树。

在 GET 上,控制树是这样的(注意自动生成的唯一 ID):

  HtmlHead
    + ctl05 : HtmlGenericControl (from your PreRender code)
    + ctl01 : Title (the <title> tag)
    + ctl02 : FavIcon (your favicon.ascx)
    + ctl04 : HtmlLink (from the 'Blue' theme)

  HtmlForm
    + ctl03 : ScriptManager

“无法加载 ViewState”错误的根本原因是:

  • 您使用 ViewState。这是一个在许多情况下可以禁用的选项。
  • 您不使用固定 ID(这就是为什么 Visual Studio 的 IDE 一直为控件添加自动但固定的 ID)。
  • 您在树中动态添加控件,较晚,因为它会更改头部的控件树。另外,您可以在其他人之前添加它 (AddAt)。

生成的 ID 遵循 ASP.NET 的lifecycle order

  1. 标题(静态)
  2. FavIcon(静态)
  3. ScriptManager(初始化)
  4. 主题(初始化,覆盖后)
  5. 动态控件(在这种情况下是在 Init 之后)

ASP.NET ViewState 引擎是一个树序列化器/反序列化器。树中的每个节点都有自己的 ID,加上一个由其父 ID 和自己的 ID 组成的“完整 ID”。当然,一旦您在序列化和反序列化之间更改 ID,所有的赌注都将关闭,引擎会检测到它并引发“Failed to Load ViewState”错误。

所以,如果您输入Visible=false,您将使用 ViewState。如果你删除它,你不会。当您自己不使用 ViewState 时,出现“加载视图状态失败”错误的可能性较小,但是当您使用其所有功能(主题等)时,ASP.NET 可以代表您使用某些 ViewState。在 Visible 的情况下,它仅表示控件存在(并使用 ViewState),但未呈现(它的 Render Size 为 0)。但是您会看到使用 ViewState 的任何其他属性的问题,它并不特定于 Visible 属性(您也可以尝试this.ViewState["test"] = "whatever")。

如果您将&lt;uc1:favicon runat="server"&gt;&lt;/uc1:favicon&gt; 放在页面的其他位置,它也将起作用,因为它不再位于 Head 控件树中,并且不会干扰 Theme 的链接或您的动态控件。

对于 Theme 和 ScriptManager,只是当你玩它们时,它会改变或不改变 ID,系统可能会检测到它。

有无数种方法可以破坏 ViewState。真正困难的是它似乎在不应该工作的时候工作(例如,只要你不使用 FavIcon 的 ViewState,你就不会注意到你的代码有问题)。

【讨论】:

    【解决方案2】:

    这是由于 ViewState 的性质而发生的。简而言之,当您的页面被回发时,ViewState 恢复到的控件与控件索引匹配,因此当索引更改时会导致此问题。 在这种情况下,以这种方式为您的页面设置属性ViewStateMode="Disabled" 或更改添加动态元素的顺序Page.Header.Controls.AddAt(Page.Header.Controls.Count, scriptControl),这样您就不会干扰恢复元素的顺序,可以帮助您应对麻烦。至少,它对我有用。

    【讨论】:

    • 你能解释一下初始加载和回发之间控制树的区别吗?如果我不动态添加 ScriptManager 而保留其他代码,为什么不会发生错误?
    • 1.最初,您的 ViewState 是空的,保存到 ViewState 的过程发生在渲染之后,此时您已经添加了所有动态控件。在 ViewState 的回发加载控件发生在呈现之前,这意味着尚未添加动态控件。这就是破坏秩序的原因。以下是有关页面生命周期顺序的更多信息:msdn.microsoft.com/en-us/library/ms972976.aspx
    • 2.另一方面,你不会一直犯这个错误,因为从 ViewState 加载时,只有元素的顺序很重要,而不是它们的类型。这意味着,有时,尽管有另一个订单,您可能不会遇到这个问题,因为预期的元素被替换为类似的元素。但是当元素完全不同时,就会导致这个错误。以下是有关此过程的更多信息以及一些相关示例:geekswithblogs.net/FrostRed/archive/2007/02/17/106547.aspx
    • 我只有在控件开头添加 Theme、scriptControl 和 FavIcon 元素 (Visible=false) 时才会遇到这个问题。 FavIcon 元素在保存到 ViewState 时的索引为 2(添加 scriptControl 后的第三个控件)。回发后,它会尝试从 ViewState 中检索它,但该位置上有 Theme (System.Web.UI.HtmlControls.HtmlLink)(尚未添加 scriptControl)。显然,这两种控件不兼容(加载状态时期望对而不是三元组的问题),从而导致错误。
    • 我没有 ScriptManager 的错误,正如您所描述的(也许是某些框架的不同版本),但我敢肯定,这种逻辑在任何情况下都是平等的。如果您尝试为您的控件重写 LoadViewState 方法以及为您的页面重写 SavePageStateToPersistenceMedium 方法并查看加载页面及其控件的顺序,这可能更容易理解。
    猜你喜欢
    • 2010-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多