视图状态压缩问题

发布于 2024-07-16 15:44:26 字数 2332 浏览 3 评论 0原文

我目前正在与 .NET Viewstate 作斗争,它开始让我疲惫不堪。 发现我们的一个应用程序中的某些页面由大约 80% 的视图状态组成后,我开始考虑尽可能减少这种情况。

我已经研究过(并且很高兴)禁用不需要它的控件(标签、按钮等)的视图状态,并在这里取得了一些小小的收获。

我现在正在研究视图状态压缩,虽然我可以证明尺寸减少了 40-50%,但它似乎不太适合我的应用程序。

设想: 页面包含一些下拉列表、一个按钮和一个 Grdiview(因此需要处理 ViewState!)。 当页面加载时,DDL 会被填充并进行默认选择。 按“确定”按钮会导致 Gridview 按预期填充。

现在的问题是:启用 Viewstate 压缩后,如果用户在单击“确定”按钮之前更改 DDL 中的选定项目,他们将收到“必需字段验证器”错误,指示尚未在其中一个 DDL 中进行选择 - 但这事实并非如此! 禁用压缩代码可以消除问题,并且页面可以按预期运行(即几个月来一直如此!)。

问题可能是由于视图状态现在存储在除 __VIEWSTATE 之外的键中[我看到的代码使用不同的键名称 - 例如 VSTATE )。

我的页面源看起来像这样;

带压缩的页面源(注意空的 __VIEWSTATE 键):

<div>
<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
<input type="hidden" name="__LASTFOCUS" id="__LASTFOCUS" value="" />
<input type="hidden" name="__VSTATE" id="__VSTATE" value="H4sIAAAAAEAO29B2AcSZYlJ
.
.
MKd2afqdaImFR5UiFXVyQPwLPA//8xt+pMsSQ8vlOklcoNgmZfJd8hHvk6/S/7UbxxAJTjzZfp6Qcm039
h3d3dvvPO7/Oa/7i57uemj1H2a/gw5lJQ+ySjFRtPZUL7A/3o2ImFR5UiFXVyLPA+38At70F1EkwAAA=" />
<input type="hidden" name="__VIEWSTATE" id="
__VIEWSTATE" value="" />
</div>

不带压缩的页面源:

<div>
<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
<input type="hidden" name="__LASTFOCUS" id="__LASTFOCUS" value="" />
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKMTYxOTM1NDg4N
A9kFgJmD2QWAgIDD2QWAgIFD2QWAmYPZBYKAgEPZBYIAgcPZBYCAgMPDxYCHgRUZXh0BRdEYXduQyBbY2hhbm
dlIHBhc3N3b3JkXWRkAgkPFgIeB1Zpc2libGVoFgQCAQ8PFgIfAAUFQWRtaW5kZAIDDw8WAh8ABQUxNDoyNGR
.
.
.
.
.
.
kAgsPDxYEHwAFWVNlbGVjdGVkIFNlcnZpY2UgVXNlcjogPGEgY2xhc3M9J3N1U2VsZWN0b3InIGhyZWY9J2xp
c3RzZXJ2aWNldXNlcnMuYXNweCc+PGI+bm9uZTwvYj48L2E+HwFoZGQCDw8QZGQWAGQCBQ8UKwADZDwrABQEA
BYSHg9QYXJlbnRJdGVtQ2xhc3MFC2lnbW5fUGFyZW50HhdUb3BMZXZlbFBhcmVudEl0ZW1DbGFzcwUTaWdtbl
Ub3BFBhcmVudB4KSlNGaWxlTmFtZWUeFlRvcExldmVsSG92ZXJJdGVtQ2xhc3MFNGlnbW5fVG9wTGV"     
/>
</div>

.NET 如何知道 VIEWSTATE 的存储位置以及它是否知道我已移动它?

除了实现 SavePageStateToPersistenceMedium 和 LoadPageStateFromPersistenceMedium 之外,我还需要对代码进行任何其他更改吗?

I'm currently fighting with the .NET Viewstate and it is starting to wear me down. Having found that some of the pages in one of our applications is made up of around 80% viewstate I have looked into reducing this where I can.

I have looked at (and am happy with) disabling viewstate for controls that do not need it (labels, buttons etc) and have made some small gains here.

I'm now looking at viewstate compression and while I can demonstrate a 40-50% decrease in size it does not seem to be playing well with my application.

Scenario:
Page contains a few dropdown lists, a button and a Grdiview (hence the need to deal with the ViewState!). When the page loads the DDLs are populated and default selections are made. Pressing the OK button results in the Gridview being populated as expected.

Now the problem: With Viewstate Compression enabled, if the user changes the selected items in the DDLs before clicking the OK button they will get a 'Required Field Validator' error indicating that a selection has not been made in one of the DDLs - but this is not the case! Disabling the compression code removes the problem and the page operates as expected (i.e. as it has for months!).

Could the problem be down to the viewstate now being stored in a key other than __VIEWSTATE [the code that I have seen use different key names - VSTATE for instance).

My page sources look like this;

Page Source with Compression (note the empty __VIEWSTATE key):

<div>
<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
<input type="hidden" name="__LASTFOCUS" id="__LASTFOCUS" value="" />
<input type="hidden" name="__VSTATE" id="__VSTATE" value="H4sIAAAAAEAO29B2AcSZYlJ
.
.
MKd2afqdaImFR5UiFXVyQPwLPA//8xt+pMsSQ8vlOklcoNgmZfJd8hHvk6/S/7UbxxAJTjzZfp6Qcm039
h3d3dvvPO7/Oa/7i57uemj1H2a/gw5lJQ+ySjFRtPZUL7A/3o2ImFR5UiFXVyLPA+38At70F1EkwAAA=" />
<input type="hidden" name="__VIEWSTATE" id="
__VIEWSTATE" value="" />
</div>

Page Source without Compression:

<div>
<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
<input type="hidden" name="__LASTFOCUS" id="__LASTFOCUS" value="" />
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKMTYxOTM1NDg4N
A9kFgJmD2QWAgIDD2QWAgIFD2QWAmYPZBYKAgEPZBYIAgcPZBYCAgMPDxYCHgRUZXh0BRdEYXduQyBbY2hhbm
dlIHBhc3N3b3JkXWRkAgkPFgIeB1Zpc2libGVoFgQCAQ8PFgIfAAUFQWRtaW5kZAIDDw8WAh8ABQUxNDoyNGR
.
.
.
.
.
.
kAgsPDxYEHwAFWVNlbGVjdGVkIFNlcnZpY2UgVXNlcjogPGEgY2xhc3M9J3N1U2VsZWN0b3InIGhyZWY9J2xp
c3RzZXJ2aWNldXNlcnMuYXNweCc+PGI+bm9uZTwvYj48L2E+HwFoZGQCDw8QZGQWAGQCBQ8UKwADZDwrABQEA
BYSHg9QYXJlbnRJdGVtQ2xhc3MFC2lnbW5fUGFyZW50HhdUb3BMZXZlbFBhcmVudEl0ZW1DbGFzcwUTaWdtbl
Ub3BFBhcmVudB4KSlNGaWxlTmFtZWUeFlRvcExldmVsSG92ZXJJdGVtQ2xhc3MFNGlnbW5fVG9wTGV"     
/>
</div>

How does .NET know where the VIEWSTATE is stored and does it know that i have moved it?

Do I need to make any other changes to my code apart from implementing SavePageStateToPersistenceMedium and LoadPageStateFromPersistenceMedium?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

仅一夜美梦 2024-07-23 15:44:26

嘿,视图状态压缩对我来说没有任何问题。 基本上我有一个用于所有使用 viewstate 的 aspx 页面的基类。 即使我使用不同的视图状态键来保存我的视图状态。 但是你必须为此重写 2 个方法:

1) - 保存视图状态
2) - 加载viewstate

只要你这样做,你应该没有问题。 请参阅下面我用于基类的代码

using System;
using System.IO;
using System.Web.UI;

namespace XC.UI.WebForms
{

    public class PageBase : System.Web.UI.Page
    {

        protected override object LoadPageStateFromPersistenceMedium()
        {
            string viewState = Request.Form["__VSTATE"];
            byte[] bytes = Convert.FromBase64String(viewState);
            bytes = XC.Common.ViewStateHelper.Decompress(bytes);
            LosFormatter formatter = new LosFormatter();
            return formatter.Deserialize(Convert.ToBase64String(bytes));
        }

        protected override void SavePageStateToPersistenceMedium(object viewState)
        {
            LosFormatter formatter = new LosFormatter();
            StringWriter writer = new StringWriter();
            formatter.Serialize(writer, viewState);
            string viewStateString = writer.ToString();
            byte[] bytes = Convert.FromBase64String(viewStateString);
            bytes = XC.Common.ViewStateHelper.Compress(bytes);
            ClientScript.RegisterHiddenField("__VSTATE", Convert.ToBase64String(bytes));
        }

    }

}

hey viewstate compression works for me without any problems. basically i have a baseclass for all my aspx pages which use viewstate. even i am using a different viewstate key to save my viewstate. however you have to override 2 methods for this:

1) - to save viewstate
2) - to load viewstate

as long as you are doing this, you should have no problems. see below code which i am using for my baseclass

using System;
using System.IO;
using System.Web.UI;

namespace XC.UI.WebForms
{

    public class PageBase : System.Web.UI.Page
    {

        protected override object LoadPageStateFromPersistenceMedium()
        {
            string viewState = Request.Form["__VSTATE"];
            byte[] bytes = Convert.FromBase64String(viewState);
            bytes = XC.Common.ViewStateHelper.Decompress(bytes);
            LosFormatter formatter = new LosFormatter();
            return formatter.Deserialize(Convert.ToBase64String(bytes));
        }

        protected override void SavePageStateToPersistenceMedium(object viewState)
        {
            LosFormatter formatter = new LosFormatter();
            StringWriter writer = new StringWriter();
            formatter.Serialize(writer, viewState);
            string viewStateString = writer.ToString();
            byte[] bytes = Convert.FromBase64String(viewStateString);
            bytes = XC.Common.ViewStateHelper.Compress(bytes);
            ClientScript.RegisterHiddenField("__VSTATE", Convert.ToBase64String(bytes));
        }

    }

}
笑梦风尘 2024-07-23 15:44:26

如果您在页面中使用ajax,请更改这行代码。 它会解决你的问题。
ClientScript.RegisterHiddenField("__VSTATE", Convert.ToBase64String(bytes));
将上面的语句替换为 ScriptManager。
ScriptManager.RegisterHiddenField(this, "__VSTATE", Convert.ToBase64String(bytes));

if you are using ajax in your page please change this line of code. It will solve your problem.
ClientScript.RegisterHiddenField("__VSTATE", Convert.ToBase64String(bytes));
replace above statement with ScriptManager.
ScriptManager.RegisterHiddenField(this, "__VSTATE", Convert.ToBase64String(bytes));

美男兮 2024-07-23 15:44:26

.NET 中隐藏着一个常量,用于保存视图状态字段名称。 我们通过挂钩您描述的方法进行压缩,但保持视图状态名称相同,没有问题。

There is a constant hidden in .NET that holds the viewstate field name. We did compression by hooking in the methods you describe but keeping the viewstate name same without issues.

初相遇 2024-07-23 15:44:26

这可能有点过分了,但是 www.strangeloop.net 上有一个非常酷的硬件解决方案可以解决这个问题。 没有隶属关系,只是对技术印象深刻。

回到页面 - 哪些类型的控件生成所有这些视图状态? 网格? 您表示您已经检查过这一点,但请注意表、td、tr、div 等设置了 runat="server" 的“不必要的 runats”。 这些控件的全部内容都保留在视图状态中。 最近,我们认识到 div 是客户端且不需要 runat="server",从而将视图状态负载减少了 40%。

This may be overkill, but there is a very cool hardware solution to this problem at www.strangeloop.net. No affiliation, just impressed by the technology.

Back to the page tho - what kinds of controls are generating all this viewstate? Grids? You indicated you went over this already, but do watch out for 'unnecessary runats' with tables, td's, tr's, div's, etc. that have runat="server" set. The entire contents of those controls get persisted in viewstate. We recently chopped 40% off our viewstate payload by recognizing a div was client-side and didn't need runat="server".

青春如此纠结 2024-07-23 15:44:26

压缩对我来说不起作用,因为它只是降低了 40%。 我有 200-300KB 的 ViewState,并且大大降低了应用程序性能。

我编写了一些视图状态替换技术,将其替换为页面上的 GUID 令牌,并将服务器本身的实际数据保存在数据库中。

这是代码和技术。

http://ashishnangla.com/2011/07/21/reducing-size-of-viewstate-in-asp-net-webforms-by-writing-a-custom-viewstate-提供者-pagestatepersister-part-12/

Compression didnt work for me as it just got it down by 40%. I had 200-300KB ViewStates and was degrading application performance drastically.

I wrote some viewstate substitution technique which replaced it with a GUID token on the page and saved the actual data on server itself in a database.

Here is the code and technique.

http://ashishnangla.com/2011/07/21/reducing-size-of-viewstate-in-asp-net-webforms-by-writing-a-custom-viewstate-provider-pagestatepersister-part-12/

滥情稳全场 2024-07-23 15:44:26

以下答案不是我的,而是OP的(包含在问题中)。 我将其排除在外,并将其设为社区维基。


我已经弄清了这个问题的真相——差不多了,我已经成功了! 由于某种原因,使用 ClientScript.RegisterHiddenField 方法似乎是问题的根源。 修改代码以利用基类保存方法,即base.SavePageStateToPersistenceMedium(compressedBytes)并处理base.LoadPageStateFromPersistenceMedium()返回的Pair对象我现在有了一个可行的解决方案。 测试显示测试页面上的性能减少了大约 70%,所以我对此非常满意。

现在我已经进行了压缩工作,我需要建议下一次(第一个正确的)代码审查将重点放在删除不需要的视图状态上。

The following answer is not mine, but OP's (that was included in the question). I'm moving it out of the question and making this a community wiki.


I've got to the bottom of this - well almost, I have it working! For some reason using the ClientScript.RegisterHiddenField method appears to have been the source of the problem. Modifying the code to utilise the base class save method, i.e. base.SavePageStateToPersistenceMedium(compressedBytes) and processing the Pair object returned by base.LoadPageStateFromPersistenceMedium() I now have a working solution. Test show a reduction of aroun 70% on the test page so I'm pretty happy with that.

Now that I have compression working I need to recommend that the next (first proper) Code Review has a focus on removing viewstate where it is not needed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文