压缩ViewState后,在Convert.FromBase64String时偶尔会发生FormatException,请教是什么原因?以下是BasePage中的相关代码        private bool viewStateCompress = false;        protected bool ViewStateCompress
        {
            set { viewStateCompress = value; }
            get { return viewStateCompress;}
        }        protected override void SavePageStateToPersistenceMedium(object state)
        {
            if (!viewStateCompress)
            { 
                base.SavePageStateToPersistenceMedium(state);
            }
            else
            {
                Pair pair;
                byte[] data;
                byte[] compressedData;
                string compressedStr;
                object viewState = null, controlState = null;                LosFormatter formatter = new LosFormatter();
                commonUtil.CompressHelper CH = commonUtil.CompressHelper.getInstance();
                PageStatePersister persister = this.PageStatePersister;                if (state is Pair)
                {
                    pair = (Pair)state;
                    viewState = pair.First;
                    controlState = pair.Second;
                }
                else
                {
                    base.SavePageStateToPersistenceMedium(state);
                    return;
                }                StringWriter wViewState = new StringWriter();
                StringWriter wControlState = new StringWriter();                formatter.Serialize(wViewState, viewState);
                string viewStateStr = wViewState.ToString();
                data = Convert.FromBase64String(viewStateStr);
                compressedData = CH.Compress(data);
                compressedStr = Convert.ToBase64String(compressedData);
                persister.ViewState = compressedStr;                formatter.Serialize(wControlState, controlState);
                string controlStateStr = wControlState.ToString();
                data = Convert.FromBase64String(controlStateStr);
                compressedData = CH.Compress(data);
                compressedStr = Convert.ToBase64String(compressedData);
                persister.ControlState = compressedStr;                persister.Save();
            }
        }        protected override object LoadPageStateFromPersistenceMedium()
        {
            if (!viewStateCompress)
            { 
                return base.LoadPageStateFromPersistenceMedium();
            }
            else
            {
                byte[] data;
                byte[] uncompressedData;
                string decompressedStr;
                object viewState, controlState;                LosFormatter formatter = new LosFormatter();
                commonUtil.CompressHelper CH = commonUtil.CompressHelper.getInstance();
                PageStatePersister persister = this.PageStatePersister;
                persister.Load();                string viewStateStr = persister.ViewState.ToString();
                string controlStateStr = persister.ControlState.ToString();
                try
                {
                    data = Convert.FromBase64String(viewStateStr);
                    uncompressedData = CH.Decompress(data);
                    decompressedStr = Convert.ToBase64String(uncompressedData);
                    viewState = formatter.Deserialize(decompressedStr);                    data = Convert.FromBase64String(controlStateStr);
                    uncompressedData = CH.Decompress(data);
                    decompressedStr = Convert.ToBase64String(uncompressedData);
                    controlState = formatter.Deserialize(decompressedStr);
                }
                catch(Exception exp)
                { 
                    viewState = null;
                    controlState = null;
                }
                return new Pair(viewState, controlState);
            }
        }

解决方案 »

  1.   

    错误发生在LoadPageStateFromPersistenceMedium中的data = Convert.FromBase64String(viewStateStr); 是一个FormatException错误,很奇怪,我放进去的时候肯定是ToBase64了,为什么拿出来的东西会不对呢?
      

  2.   

    处理过程中没有必要设计base64编码。不论你写出什么二进制值,之后会被重新编码。而读入之前也会自动解码。因此你如果进行bas64编码,应该是额外多做了一道。另外,压缩之前也没有必要base64编码。
      

  3.   

    我只知道viewstate默认是Base64形式的数据
      

  4.   

    当Convert.FromBase64String方法的参数s的长度小于 4 或不是 4 的偶数倍时,将会抛出FormatException。
    参考
    http://www.cnblogs.com/heliguan/articles/1060481.html
      

  5.   

    不知道你的 commonUtil.CompressHelper 是什么,所以没法测试。我其实怀疑这样能够压缩多少。执行压缩,并且仍然是通过internet上无数的网卡、网线、路由器来回传递,这还是比较复杂的过程。我写了一个简单的过程,不压缩,用磁盘来代替网络,可以参考一下。这里也是输出字符串,但是并不做base64编码解码。
    public class XVPage : Page
    {
        static private DirectoryInfo _Dir;    private DirectoryInfo Dir
        {
            get
            {
                if (_Dir == null)
                {
                    _Dir = new DirectoryInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "App_Data"));
                    if (!_Dir.Exists)
                        _Dir.Create();
                    _Dir = new DirectoryInfo(Path.Combine(_Dir.FullName, "ViewState"));
                    if (!_Dir.Exists)
                        _Dir.Create();
                }
                return _Dir;
            }
        }    protected override object LoadPageStateFromPersistenceMedium()
        {
            PageStatePersister ps = this.PageStatePersister;
            ps.Load();
            if (ps.ControlState != null)
                ps.ControlState = 反序列化对象((string)ps.ControlState);
            if (ps.ViewState != null)
                ps.ViewState = 反序列化对象((string)ps.ViewState);
            return new Pair(ps.ControlState, ps.ViewState);
        }    protected override void SavePageStateToPersistenceMedium(object state)
        {
            PageStatePersister ps = this.PageStatePersister;
            if (state is Pair)
            {
                Pair pair = (Pair)state;
                ps.ControlState = pair.First;
                ps.ViewState = pair.Second;
            }
            else
            {
                ps.ViewState = state;
            }
            if (ps.ControlState != null)
                ps.ControlState = 序列化对象(ps.ControlState);
            if (ps.ViewState != null)
                ps.ViewState = 序列化对象(ps.ViewState);
            ps.Save();
        }    private object 反序列化对象(string stateID)
        {
            string stateStr = (string)Cache[stateID];
            string file = Path.Combine(Dir.FullName, stateID);
            if (stateStr == null)
                stateStr = File.ReadAllText(file);
            else
                Cache.Remove(stateID);
            return new ObjectStateFormatter().Deserialize(stateStr);
        }    private string 序列化对象(object obj)
        {
            string value = new ObjectStateFormatter().Serialize(obj);
            string stateID = (DateTime.Now.Ticks + (long)value.GetHashCode()).ToString(); //产生离散的id号码   
            File.WriteAllText(Path.Combine(Dir.FullName, stateID), value);
            Cache.Insert(stateID, value);
            return stateID;
        }    protected override void OnUnload(EventArgs e)
        {
            base.OnUnload(e);
            DateTime dt = DateTime.Now.AddMinutes(-20);
            foreach (FileInfo fl in Dir.GetFiles())
                if (fl.LastAccessTime < dt)
                    try
                    {
                        fl.Delete();
                    }
                    catch
                    {
                    }
        }
    }
      

  6.   

    你不会是仅仅为了在string与byte[]之间转换就动用了Base64编码解码功能了吧?在调用compressedData = CH.Compress(data);前后,都无需Base64解码和编码,直接把compressedData 从byte[]转换为string就可以了(无需编码)。
      

  7.   

    多谢sp1234,存放viewstate到文件的做法我也考虑过,可是由于我们服务器上不允许,所以就采用了压缩的办法,对于一些大页面非常有用。我原来的想法是因为viewstate是base64编码的,所以我就ConvertFromBase64->Compress->ConvertToBase64->SaveViewState。先前我采用的是RegisterHiddenField的做法,所以是手工Base64,如果直接存取persist对象可以自动转换base64的话那就太好了。我再debug一下试试看。