编程点滴,目前主要研究Android

对待生活,应该怀着一颗感恩的心

首页 新随笔 联系 订阅 管理
为了节省带宽,可能需要压缩一下 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 上也没说太明白,哪位大虾解释一下?

参考

posted on 2007-05-02 18:09  chengbo  阅读(4102)  评论(8编辑  收藏  举报