为什么当我尝试将2D数组封装在属性中以在回发之间持久化时,会出现损坏的ViewState错误

本文关键字:持久化 之间 ViewState 错误 损坏 2D 数组 为什么 属性 封装 | 更新日期: 2023-09-27 18:29:25

基本上,我正在尝试使用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];
        }
    }
}

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

我的想法是将它重构成这样的东西,因为有大量代码使用这个对象,而且实际应用程序中还有更多的对象。我想在修改尽可能少的代码的同时解决这个问题(重新arper可以很容易地将字段移到一个单独的类中,并将它们转换为属性。然后我修改了属性代码,以使用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和boolean,它们都可以使用此方法按预期工作。但当我把一个2d阵列加入到混合中时,我会得到以下错误:

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

来源错误:

【无相关源线】

堆栈跟踪:

[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数组的回发之间持久化对象,但没有其他类型的对象时,为什么会出现这个错误,有什么想法吗?

干杯

为什么当我尝试将2D数组封装在属性中以在回发之间持久化时,会出现损坏的ViewState错误

据我所知,多维数组不是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();
}