人无信不立/2008-04-26 22:30

C#强化系列文章一:ViewState使用兼谈序列化

ViewState的使用比较简单,一两句话就可以了。
赋值:ViewState[key] = value;
取值:value = ViewState[key];

最主要的作用就是可以在当前页面保存值,ASP.NET的页面状态维护就是使用ViewState来实现的,基本上每一个ASPX页面都可以看到如下类似的html代码:
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKMTkwNjc4NTIwMWRkyv4ncofW5vaWXdXRtXfXn3RYQR4=" />
也就是说ViewState中的值实际上都是通过一个hidden来保存的,hidden的name为__VIEWSTATE,那么如果页面上有另外一个控件的名称也叫:__VIEWSTATE的话,会导致页面出错。
其实在我们进行页面开发或者进行自定义控件开发的时候,都可以使用ViewState,很方便。

ViewState是ASP.NET中特有的,相对于Session来说,它保存的值只能在当前页面使用,并且保存的只能是已经序列化的类,比如.NET中的strings, integers, Booleans, arrays, ArrayList, hashtable,DataTable等。
那么如何将自定义的类放入ViewState中呢,这个就涉及到如下所说的序列化的问题了:
序列化简单来说就是把一个对象转化成一种可以持久保存的数据,当下次需要使用时再把之前保存的数据反序列化成一个对象。
当然在.NET中提供了简便的方法进行序列化的操作。
下面我以一个简单的例子来说明
将自定义类Test保存到viewstate中的按钮事件代码:
    protected void Button1_Click(object sender, EventArgs e)
    
{
        Test test 
= ViewState["VIEW_TEST"as Test;
        
if (test == null)
        
{
            test 
= new Test();
        }

        test[
-1= TextBox1.Text;

        ViewState[
"VIEW_TEST"= test;
    }

下面再看一下自定义类Test的实现:
[SerializableAttribute]
class Test
{
    
private IList list;

    
public Test()
    
{
        list 
= new ArrayList();
    }


    
public object this[int index]
    
{
        
get
        
{
            
if (index >= list.Count)
            
{
                
return null;
            }

            
return list[index];
        }

        
set
        
{
            list.Add(value);
        }


    }

}
特别注意第一行的SerializableAttribute属性,指定这个属性后就代表此类是可以序列化的(具体序列化的过程都是由.NET内部进行的),那么我们就可以把此类放入ViewState中了,如果没有指定SerializableAttribute属性的话,放入ViewState时就会报错。

以上所示是序列化的第一种方式:基本序列化,也是比较简单的一种,如果是复杂情况就要使用下面所说的第二种序列化的方式:自定义序列化
假设我们的Test类需要从DataTable继承:
[SerializableAttribute]
class Test : DataTable
{
    
public Test()
    
{
        DataColumn col 
= new DataColumn();
        col.DataType 
= typeof(string);
        col.ColumnName 
= "name";
        
this.Columns.Add(col);
    }


    
public object this[int index]
    
{
        
get
        
{
            
if (index >= Rows.Count)
            
{
                
return null;
            }

            
return Rows[index]["name"];
        }

        
set
        
{
            DataRow row 
= NewRow();
            row[
"name"= value;
            Rows.Add(row);
        }

    }

}
那么再把这个类放入ViewState的话就会报错:此页的状态信息无效,可能已损坏,主要是因为它的父类DataTable中的DataRow和DataColumn等是不可序列化的,我们就需要把这个类改造成如下形式:
[SerializableAttribute]
class Test : DataTable, System.Runtime.Serialization.ISerializable
{
    
public Test()
    
{
        DataColumn col 
= new DataColumn();
        col.DataType 
= typeof(string);
        col.ColumnName 
= "name";
        
this.Columns.Add(col);
    }


    
public object this[int index]
    
{
        
get
        
{
            
if (index >= Rows.Count)
            
{
                
return null;
            }

            
return Rows[index]["name"];
        }

        
set
        
{
            DataRow row 
= NewRow();
            row[
"name"= value;
            Rows.Add(row);
        }

    }


    
public Test(SerializationInfo info, StreamingContext context)
    
{
        DataColumn col 
= new DataColumn();
        col.DataType 
= typeof(string);
        col.ColumnName 
= "name";
        
this.Columns.Add(col);

        ArrayList list 
= info.GetValue("list"typeof(ArrayList)) as ArrayList;
        
foreach (string value in list)
        
{
            DataRow row 
= NewRow();
            row[
"name"= value;
            Rows.Add(row);
        }

    }


    
public void GetObjectData(SerializationInfo info, StreamingContext context)
    
{
        ArrayList list 
= new ArrayList();
        
foreach (DataRow row in this.Rows)
        
{
            list.Add(row[
"name"]);
        }
 
        info.AddValue(
"list", list);
    }


}
1、实现ISerializable接口
2、实现GetObjectData方法,这个方法中就是把要序列化的对象放入info中,特别注意放入info中的对象本身必须是可以序列化的,如果放入一个DataRow对象,就会报错:未标记为可序列化
3、实现public Test(SerializationInfo info, StreamingContext context) 构造函数,这个函数就是一个反序列化的操作,把info中的对象取出来
经过上面的改造之后,就可以把这个Test对象放入ViewState中了
posted @ 2007-11-20 17:33 永春 阅读(3512) 评论(16)  编辑 收藏 所属分类: .Net

  回复  引用    
#1楼 2007-11-20 17:56 | xmanx [未注册用户]
为什么不考虑压缩,并且转换为 byte[]放入ViewSate,Session等等。

你可以参考
http://www.cnblogs.com/mail-ricklee/archive/2007/10/19/930661.html
中的压缩保存模式
  回复  引用  查看    
#2楼 2007-11-20 19:56 | 代码乱了      
@xmanx
压缩?也要涉及到序列化,反序列化这个问题的
  回复  引用  查看    
#3楼 2007-11-20 21:00 | PureEviL      
--引用--------------------------------------------------
xmanx: 为什么不考虑压缩,并且转换为 byte[]放入ViewSate,Session等等。

你可以参考
<a href="http://www.cnblogs.com/mail-ricklee/archive/2007/10/19/930661.html" target="_new" rel="nofollow">http://www.cnblogs.com/mail-ricklee/archive/2007/10/19/930661.html</a>
中的压缩保存模式
--------------------------------------------------------
不觉得压缩ViewState有啥明星优势
  回复  引用  查看    
#4楼 [楼主]2007-11-20 21:33 | GSpring      
@PureEviL
压缩也就是可以减少一点网络传输量

正如 代码乱了 所说,还是要考虑序列化问题的
  回复  引用  查看    
#5楼 2007-11-21 09:07 | 马可香蕉      
以前用viewstate直接存过datatable,当datatable过大时,速度实在是太慢了.....

但是没有出现过报错的现象啊
  回复  引用  查看    
#6楼 [楼主]2007-11-21 09:38 | GSpring      
@马可香蕉
的确DataTable是可以序列化的,我刚才反编译看了一下,是有
Serializable标志的,谢谢你的提醒

不过,当一个自定义类从DataTable继承之后就不能直接放入ViewState了,需要进行如上的处理
  回复  引用  查看    
#7楼 2007-11-21 13:29 | henry      
一般都会用IStateManage实现状态处理,这样对状态加载或保存可控性更高.
  回复  引用  查看    
#8楼 2007-11-21 13:50 | BrianLei      
ViewState All You Wanted to Know 可以补充一下“最主要的作用”
http://aspalliance.com/articleViewer.aspx?aId=135&pId=
  回复  引用  查看    
#9楼 [楼主]2007-11-21 13:56 | GSpring      
@henry
这也是一种方法

@BrianLei
谢谢,老外的这篇文章写的不错,主要是从原理上来分析ViewState的
  回复  引用  查看    
#10楼 2007-11-21 19:11 | 壁虎      
ViewState应该少用。数据量一大,那个页面就会暴涨。
  回复  引用  查看    
#11楼 [楼主]2007-11-21 21:02 | GSpring      
@壁虎
的确是的,不过在有的情况下,实在没办法还是要用一点的。毕竟使用Session也不太好的
  回复  引用  查看    
#12楼 2008-04-28 09:37 | <∩扫地僧∩>      
List<string>可以保存在session中么?
  回复  引用  查看    
#13楼 [楼主]2008-04-28 12:32 | 永春      
@&lt;∩扫地僧∩&gt;
可以的
  回复  引用    
#14楼 2008-07-06 12:59 | 傅军 [未注册用户]
我好像试验了一下那个继承DataTable的Test类,但是给类加了[SerializableAttribute]以后好像就可以正常运行了,并没有报错。我看了一下DataRow的类定义,确实没有标记为“SerializableAttribute”,也没有实现ISerializable接口,不是很明白为什么会出现这种情况。

我是使用Asp.net2.0。

请博主不惜赐教,谢谢:)
  回复  引用  查看    
#15楼 [楼主]2008-07-07 12:35 | 永春      
@傅军
你在页面上再放入一个按钮,然后在这个按钮事件中存取viewstate就会抱错了

标题  
姓名  
主页
Email (只有博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2008-01-31 14:33 编辑过


相关链接: