1

基本上我正在尝试使用 ViewState 在回发之间保留对象。此外,我试图将这些对象封装在私有类的属性中。

这样做的目的是重构以前使用静态字段来持久化对象的现有代码,这显然会导致问题。

所以这是一个非常简单的 Web 表单 HTML 示例:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="WebApplication3.WebForm1" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>

        <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
        <br />
        <asp:Button ID="Button1" runat="server" Text="Button" />

    </div>
    </form>
</body>
</html>

这是一个非常简单的初始代码隐藏示例(不是我自己编写的):

using System;
using System.Web.UI;

namespace WebApplication3
{
    public partial class WebForm1 : Page
    {
        private static string[,] _my2DArray;

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                _my2DArray = new string[3,3];

                for (var i = 0; i < 3; i++)
                {
                    for (var j = 0; j < 3; j++)
                    {
                        _my2DArray[i, j] = Guid.NewGuid().ToString();
                    }
                }
            }

            TextBox1.Text = _my2DArray[1, 1];
        }
    }
}

这实现了在回发之间持久化对象的目标,但会导致问题,因为它也会在其他所有事物之间持久化对象。

我的想法是将它重构为这样的东西,因为有很多使用这个对象的代码隐藏,并且在实际应用程序中还有更多的对象。我想在更改尽可能少的代码的同时解决问题(resharper 可以轻松地将字段移出到单独的类中,并将它们转换为属性。然后我修改了属性代码以使用 Viewstate 而不是私有支持场地):

using System;
using System.Web.UI;

namespace WebApplication3
{
    public partial class WebForm1 : Page
    {
        internal class MyClass
        {
            private readonly WebForm1 _webForm1;

            internal MyClass(WebForm1 webForm1)
            {
                _webForm1 = webForm1;
            }

            internal string[,] My2DArray
            {
                set { _webForm1.ViewState["_my2DArray"] = value; }
                get { return (string[,])_webForm1.ViewState["_my2DArray"]; }
            }
        }

        private MyClass _myClass;

        protected void Page_Load(object sender, EventArgs e)
        {
            _myClass = new MyClass(this);

            if (!IsPostBack)
            {
                _myClass.My2DArray = new string[3,3];

                for (var i = 0; i < 3; i++)
                {
                    for (var j = 0; j < 3; j++)
                    {
                        _myClass.My2DArray[i, j] = Guid.NewGuid().ToString();
                    }
                }
            }

            TextBox1.Text = _myClass.My2DArray[1, 1];
        }
    }
}

这几乎奏效了。除了 2D 数组之外,还有字符串 int 和 booleans,它们都可以使用此方法按预期工作。但是当我将二维数组加入混合时,我得到以下错误:

此页面的状态信息无效,可能已损坏。

源错误:

[没有相关的源代码行]

堆栈跟踪:

[EndOfStreamException: Unable to read beyond the end of the stream.]
   System.IO.BinaryReader.ReadByte() +9616466
   System.Web.UI.ObjectStateFormatter.DeserializeValue(SerializerBinaryReader reader) +44
   System.Web.UI.ObjectStateFormatter.DeserializeValue(SerializerBinaryReader reader) +380
   System.Web.UI.ObjectStateFormatter.Deserialize(Stream inputStream) +141

[ArgumentException: The serialized data is invalid.]
   System.Web.UI.ObjectStateFormatter.Deserialize(Stream inputStream) +205
   System.Web.UI.ObjectStateFormatter.Deserialize(String inputString) +337
   System.Web.UI.ObjectStateFormatter.System.Web.UI.IStateFormatter.Deserialize(String serializedState) +4
   System.Web.UI.Util.DeserializeWithAssert(IStateFormatter formatter, String serializedState) +37
   System.Web.UI.HiddenFieldPageStatePersister.Load() +147

[ViewStateException: Invalid viewstate. 
    Client IP: 127.0.0.1
    Port: 
    Referer: http://localhost:27314/WebForm1.aspx
    Path: /WebForm1.aspx
    User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.62 Safari/537.36
    ViewState: /wEPDwULLTE0MDM4MzYxMjMPFgIeBkZvb2JhcmRkem7xFcvXyGXVXNDDKHSutQ9j/EhfbWTpihkzXIlH66A=]

[HttpException (0x80004005): The state information is invalid for this page and might be corrupted.]
   System.Web.UI.ViewStateException.ThrowError(Exception inner, String persistedState, String errorPageMessage, Boolean macValidationError) +198
   System.Web.UI.ViewStateException.ThrowViewStateError(Exception inner, String persistedState) +14
   System.Web.UI.HiddenFieldPageStatePersister.Load() +251
   System.Web.UI.Page.LoadPageStateFromPersistenceMedium() +106
   System.Web.UI.Page.LoadAllState() +43
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +8431
   System.Web.UI.Page.ProcessRequest(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +253
   System.Web.UI.Page.ProcessRequest() +78
   System.Web.UI.Page.ProcessRequestWithNoAssert(HttpContext context) +21
   System.Web.UI.Page.ProcessRequest(HttpContext context) +49
   ASP.webform1_aspx.ProcessRequest(HttpContext context) in c:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\root\37286ff3\6dc3cf92\App_Web_t5caigbu.0.cs:0
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +100
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +75

我难住了。如果您在 VS 中创建一个新的 Webforms 解决方案并将上面的 HTML + 代码复制到它们各自的文件中,那么您将拥有我所拥有的。

我正在使用 Visual Studio 2010 并以 .Net 4 为目标。

当我使用此方法在具有 2D 数组的回发之间保留对象但没有其他类型的对象时,为什么会出现此错误的任何想法?

干杯

4

1 回答 1

1

据我记得多维数组不是XmlSerializable,是ViewState使用的序列化方式。

至于会话,只要你使用 InProc 模式,对象就会存储在内存中,你不会遇到这个问题。如果您尝试使用需要 xml 序列化的会话机制,例如数据库存储,问题将是相同的。

如果可能的话:

  • 更改您的二维数组的类型:例如,String[][]在您的许多页面中更改为数​​组 () 数组...
  • 如果您的页面有一个共同的层次结构,也许您可​​以尝试覆盖SaveViewStateLoadViewState执行数组的自定义序列化。

没试过,但我第一次尝试覆盖看起来像这样

protected override void LoadViewState(object savedState)
{
    base.LoadViewState(savedState);

    string[,] my2DArray = myMethodForDeserializing2DArrayFromCustomFormat(ViewState["my2DArray"]);
    ViewState["my2DArray"] = my2DArray;
}

protected override object SaveViewState()
{
    string my2DArraySerialized = myMethodForSerializing2DArrayToCustomFormat(ViewState["my2DArray"]);
    ViewState["my2DArray"] = my2DArraySerialized;
    return base.SaveViewState();
}
于 2013-08-30T07:58:54.853 回答