惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hacker News: Front Page
P
Palo Alto Networks Blog
T
ThreatConnect
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
T
True Tiger Recordings
P
Privacy & Cybersecurity Law Blog
B
Blog
IT之家
IT之家
Last Week in AI
Last Week in AI
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
C
Comments on: Blog
Microsoft Azure Blog
Microsoft Azure Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
N
News and Events Feed by Topic
NISL@THU
NISL@THU
腾讯CDC
雷峰网
雷峰网
Security Latest
Security Latest
李成银的技术随笔
M
Microsoft Research Blog - Microsoft Research
L
LangChain Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Check Point Blog
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
博客园 - Franky
N
News | PayPal Newsroom
V
V2EX
A
About on SuperTechFans
The Register - Security
The Register - Security
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
MyScale Blog
MyScale Blog
Cisco Talos Blog
Cisco Talos Blog
Vercel News
Vercel News
WordPress大学
WordPress大学
C
Cyber Attacks, Cyber Crime and Cyber Security
The Hacker News
The Hacker News
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
爱范儿
爱范儿
A
Arctic Wolf
L
LINUX DO - 最新话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - chengbo

Android Studio:为Android定制的IDE 使用Gitolite来对Git的repository实现权限控制 用Debian当路由,来解决BT造成的网络慢的问题 更快的,更好的支持硬件的模拟器 当LISTVIEW有HEADER时,ONITEMCLICK里的POSITION不正确 准备再写写东西了 如何让 firefox 的窗口大小不再被网页脚本改变 52个行之有效的减压方法 用Javascript检查Caps Lock是否按下 如何用C#和SQL获得当前月的第一天和最后一天 每天如何自动编译项目并将之打包添加到VSS中 - chengbo - 博客园 maxthon 2 预览版的邀请 成都古羌科技有限公司招聘 怎样用TSQL建JOB xml参数存储过程 如何在ReadOnly的DataGrid中的让CheckBox列可点击 激情黄健翔 Head first design patterns 读书笔记 – Strategy(策略模式) 双击U盘出现“拒绝访问”的解决方法
压缩 ViewState 后,与 UpdatePanel 的兼容问题 - chengbo
chengbo · 2007-05-02 · via 博客园 - chengbo

为了节省带宽,可能需要压缩一下 ViewState ,具体压缩的代码,网上一搜一大把,比如下面这段:

public class CompressedViewStatePage : System.Web.UI.Page
{
    
const string CompressedViewStateKey = "__COMPRESSEDVIEWSTATE";
    
protected override void SavePageStateToPersistenceMedium(object state)
    
{
        LosFormatter formatter 
= new LosFormatter();
        StringWriter writer 
= new StringWriter();
        formatter.Serialize(writer, state);
        
string viewState = writer.ToString();
        
byte[] data = Convert.FromBase64String(viewState);
        
byte[] compressedData = CompressHelper.Compress(data);
        
string str = Convert.ToBase64String(compressedData);
        ClientScript.RegisterHiddenField(CompressedViewStateKey, str);
    }


    
protected override object LoadPageStateFromPersistenceMedium()
    
{
        
string viewState = Request.Form[CompressedViewStateKey];
        
byte[] data = Convert.FromBase64String(viewState);
        
byte[] uncompressedData = CompressHelper.Decompress(data);
        
string str = Convert.ToBase64String(uncompressedData);
        LosFormatter formatter 
= new LosFormatter();
        
return formatter.Deserialize(str);
    }

}

这个方法重写了 Page.SavePageStateToPersistenceMedium 和 Page.LoadPageStateFromPersistenceMedium 方法。代码注册了一个 __COMPRESSEDVIEWSTATE 的隐藏字段,把压缩的 ViewState 放在其中,不再使用原先的 __VIEWSTATE 字段。

我要做的一个页面的情况是,顶部有很多选择查询参数的控件,用户首先输入参数,再点击搜索按钮后系统会把搜索出来的记录集显示在 UpdatePanel 里的 GridView 上;若不选择参数, GridView 上会显示数据库中所有的记录集。使用上面的代码在未启用局部刷新时没有问题,但是启用的话,假如用户第一次选择了一些参数,搜索,GridView 会绑定显示搜索出来的记录集,但是这时点击 GridView 的分页按钮, GridView 重新显示的却是所有记录集,也就是说, ViewState 丢失了。

禁用 Ajax 或不用上面的方法压缩 ViewState ,都可以恢复正常,但如果我两个都想要呢?好在这世上有 Google 这东西,我搜索到了下面的解决方案:

public class CompressedViewStatePage : System.Web.UI.Page
{
    protected override void SavePageStateToPersistenceMedium(object state)
    
{
        Pair pair;
        PageStatePersister persister 
= this.PageStatePersister;
        
object viewState;
        
if (state is Pair)
        
{
            pair 
= (Pair)state;
            persister.ControlState 
= pair.First;
            viewState 
= pair.Second;
        }

        
else
        
{
            viewState 
= state;
        }


        LosFormatter formatter 
= new LosFormatter();
        StringWriter writer 
= new StringWriter();
        formatter.Serialize(writer, viewState);
        
string viewStateStr = writer.ToString();
        
byte[] data = Convert.FromBase64String(viewStateStr);
        
byte[] compressedData = CompressHelper.Compress(data);
        
string str = Convert.ToBase64String(compressedData);

        persister.ViewState 
= str;
        persister.Save();
    }


    
protected override object LoadPageStateFromPersistenceMedium()
    
{
        PageStatePersister persister 
= this.PageStatePersister;
        persister.Load();

        
string viewState = persister.ViewState.ToString();
        
byte[] data = Convert.FromBase64String(viewState);
        
byte[] uncompressedData = CompressHelper.Decompress(data);
        
string str = Convert.ToBase64String(uncompressedData);
        LosFormatter formatter 
= new LosFormatter();
        
return new Pair(persister.ControlState, formatter.Deserialize(str));
    }

}

如果用 Reflector 看看 System.Web.UI.Page 类的 SavePageStateToPersistenceMedium 和 LoadPageStateFromPersistenceMedium 方法,你会发现上面的代码和微软的实现差不多,都是使用 Persister.Save 和 Persister.Load 来保存和获取 ViewState (只是上面的代码加上了压缩和解压的逻辑),这里的 Persister 是默认的 HiddenFieldPageStatePersister ,所以页面还是使用 __VIEWSTATE 字段来保存 ViewState。

改成第二段代码来压缩 ViewState 就正常了。至于第一段代码会在 Update Panel 中出问题,我是这样猜的:

启用 UpdatePanel 的局部刷新并不是真正的局部刷新,只不过微软做了点手脚,用 XMLHttpRequest 对象去向服务器提交请求,而服务器毫不知情,还是会生成一个完整的页面生成周期,把生成的 HTML 完整的返回,这时 ScriptManager 把不在 UpdatePanel 里的内容统统去掉,只接收 UpdatePanel 里面的内容,然后在客户端刷新一下,造成局部刷新的“假像”。问题就出在用 XMLHttpRequest 对象去请求服务器的时候,ScriptManager 不知道我们把 ViewState 放在 __COMPRESSEDVIEWSTATE 字段中,而用的是 __VIEWSTATE 字段里的内容,所以服务器会认为用户没有输入查询参数,返回了数据库中的所有记录……

问题好像就是这样产生的,不过我还有点不清楚,Persister.ControlState 和 Persister.ViewState 各是什么意思, MSDN 上也没说太明白,哪位大虾解释一下?

参考