欢迎光临
我们一直在努力

ViewState 剖析(翻译兼笔记)-ASP教程,ASP应用

建站超值云服务器,限时71元/月

viewstate 不是什么?

1. viewstate 不是用来恢复回发的控件的值。

这个是通过匹配 form 中该控件的变量名而自动完成的。这个只对 load 事件加载之前创建的控件有效。

2. viewstate 不会自动重新创建任何通过代码动态创建的控件。

3. 不是用来保存用户信息的。仅仅保存本页的控件状态,而不能在页面之间传递。

viewstate 是什么?

viewstate 用来跟踪和保存控件的状态信息。否则这些信息可能会丢失,原因可能是这些值不随着 form 回发,或者根本就不在 page 的 html 中。

viewstate 中保存着代码中改变的控件属性,通过代码绑定到控件的任何数据,以及由用户操作触发,回发的任何更改。

viewstate 还提供了一个状态包(statebag), 这是一个特殊的集合或字典(collection or dictionary), 可以用来保存,通过一个 key 来恢复任意的对象或者值。

viewstate 的格式

保存在表单中的 __viewstate 隐藏字段。是 base64 编码过的,而不是加密!

但要加密也是可以的(设置 enableviewstatemac 来使用 machine key 进行 hash)

加密:设置 machinekey 验证, 但这必须在机器级别设置,需要更多的资源,所以不推荐。

listing 1: viewstate machine hash disabled

machine.config or web.config: <pages enableviewstatemac=false />

page level directive: <%@page enableviewstatemac=false %>

page level script code: page.enableviewstatemac = false;

listing 2: viewstate encryption is enabled

machine.config: <machinekey validation=3des validationkey=* />

where the validationkey must be the same across a web-farm setup

also requires the enableviewstatemac property setting to be true

在 rendering 之前,viewstate 在 page.savepagestatetopersistencemedium 方法中被保存,

回发时,在 page.loadpagestatefrompersistancemedium 方法中被恢复。

这两个方法都可以轻易的被重写,从而实现保存 viewstate 到 session 中。这适合于带宽小的场合,

如移动设备默认是采用 session.代码如下:

listing 3: viewstate saved in session state

protected override object loadpagestatefrompersistencemedium()

{

return session["viewstate"];

}

protected override void savepagestatetopersistencemedium(object viewstate)

{

session["viewstate"] = viewstate;

// bug requires hidden form field __viewstate

registerhiddenfield("__viewstate", "");

}

如果要把 viewstate 通过数据库或其他持久化设备来维持,则需要采用特定的 losformatter 类来序列化,反序列化。(serialize, deserialize)

listing 4: viewstate saved in custom store

protected override object loadpagestatefrompersistencemedium()

{

losformatter format = new losformatter();

return format.deserialize(yourdatastore["viewstate"]);

}

protected override void savepagestatetopersistencemedium(object viewstate)

{

losformatter format = new losformatter();

stringwriter writer = new stringwriter();

format.serialize(writer, viewstate);

yourdatastore["viewstate"] = writer.tostring();

}

最后,我们来看一下 viewstate 的内部格式到底是什么。

每个控件的 viewstate 保存在一个三元组中(triplet, system.web.ui.triplet).

其 first 对象是:

一个 pair(system.web.ui.pair)



array or pairs, of arraylists of related name-values.

second 对象:

该控件在控件树中的索引的 arraylist

third 对象:

子控件的类似的三元组的 arraylist

listing 5: viewstate decode/parse example

编码后的 viewstate:

ddwxmjm0nty3odkwo3q8cdxsphbycee7chjwqjtwcnbdoz47bdx2ywxbo3zhbei7dmfsqzs+pjtspgk8

md47atwypjtppdm+o2k8nt47pjtsphq8cdxsphbycee7chjwqjs+o2w8dmfsqtt2ywxcoz4+ozs+o3q8

cdxsphbycee7chjwqjs+o2w8dmfsqtt2ywxcoz4+ozs+o3q8cdxsphbycee7chjwqjs+o2w8dmfsqtt2

ywxcoz4+ozs+o3q8cdxsphbycee7chjwqjs+o2w8dmfsqtt2ywxcoz4+ozs+oz4+oz4=

解码后的 viewstate:

t<1234567890;t<p<l<prpa;prpb;prpc;>;l<vala;valb;valc;>>;

l<i<0>;i<2>;i<3>;i<5>;>;l<

t<p<l<prpa;prpb;>;l<vala;valb;>>;;>;

t<p<l<prpa;prpb;>;l<vala;valb;>>;;>;

t<p<l<prpa;prpb;>;l<vala;valb;>>;;>;

t<p<l<prpa;prpb;>;l<vala;valb;>>;;>;>>;>

解析后的 viewstate:

t<1234567890; 页面级别的三元组是特例

t<p<l<prpa;prpb;prpc;>; triplet-first:pair-first:arraylist

l<vala;valb;valc;> pair-second:arraylist

>;

l<i<0>; triplet-second:arraylist:indices

i<2>; of the

i<3>; children

i<5>; controls

>;

l<t<p<l<prpa;prpb;>; triplet-third:arraylist:triplets

l<vala;valb;> of the

>; children

; controls

>;

t<p<l<prpa;prpb;>; each sub-triplet follows same pattern

l<vala;valb;>

>;

; more levels possible if sub-children

>;

t<p<l<prpa;prpb;>; each sub-triplet follows same pattern

l<vala;valb;>

>;

; more levels possible if sub-children

>;

t<p<l<prpa;prpb;>; each sub-triplet follows same pattern

l<vala;valb;>

>;

; more levels possible if sub-children

>;

>

>; closing of special page-level triplet

>

listing 6: viewstate decode/parse code

1using system;

2using system.collections;

3using system.componentmodel;

4using system.data;

5using system.drawing;

6using system.web;

7using system.web.sessionstate;

8using system.web.ui;

9using system.web.ui.webcontrols;

10using system.web.ui.htmlcontrols;

11using system.io;

12using system.text;

13

14namespace myplayground

15{

16 /// <summary>

17 /// showviewstate 的摘要说明。

18 /// </summary>

19 public class showviewstate : system.web.ui.page

20 {

21 private void page_load(object sender, system.eventargs e)

22 {

23 //trace.warn("分类名称", "^_^,这是警告!自动用红色字显示");

24 //trace.write("这是普通的消息写入!");

25 }

26 #region web 窗体设计器生成的代码 …

27

28 override protected void oninit(eventargs e)

29 {

30 //

31 // codegen: 该调用是 asp.net web 窗体设计器所必需的。

32 //

33 initializecomponent();

34 base.oninit(e);

35 }

36

37 /// <summary>

38 /// 设计器支持所需的方法 – 不要使用代码编辑器修改

39 /// 此方法的内容。

40 /// </summary>

41 private void initializecomponent()

42 {

43 this.load += new system.eventhandler(this.page_load);

44

45 }

46 #endregion

47

48 protected override void savepagestatetopersistencemedium(object viewstate)

49 {

50 // 调用基类的方法以便不影响正常的处理

51 base.savepagestatetopersistencemedium(viewstate);

52 // 读取 viewstate 并写到页面

53 losformatter format = new losformatter();

54 stringwriter writer = new stringwriter();

55 format.serialize(writer, viewstate);

56 string vsraw = writer.tostring();

57 response.write("viewstate raw: " + server.htmlencode(vsraw) + "<hr>");

58 // 解码 viewstate 并写到页面

59 byte[] buffer = convert.frombase64string(vsraw);

60 string vstext = encoding.ascii.getstring(buffer);

61 response.write("viewstate text: " + server.htmlencode(vstext) + "<hr>");

62 // 解析 viewstate — 打开页面跟踪(tracing)

63 parseviewstate(viewstate, 0);

64 }

65 private void parseviewstate(object vs, int level)

66 {

67 if (vs == null)

68 {

69 trace.warn(level.tostring(), spaces(level) + "null");

70 }

71 else if (vs.gettype() == typeof(system.web.ui.triplet))

72 {

73 trace.warn(level.tostring(), spaces(level) + "triplet");

74 parseviewstate((triplet) vs, level);

75 }

76 else if (vs.gettype() == typeof(system.web.ui.pair))

77 {

78 trace.warn(level.tostring(), spaces(level) + "pair");

79 parseviewstate((pair) vs, level);

80 }

81 else if (vs.gettype() == typeof(system.collections.arraylist))

82 {

83 trace.warn(level.tostring(), spaces(level) + "arraylist");

84 parseviewstate((ienumerable) vs, level);

85 }

86 else if (vs.gettype().isarray)

87 {

88 trace.warn(level.tostring(), spaces(level) + "array");

89 parseviewstate((ienumerable) vs, level);

90 }

91 else if (vs.gettype() == typeof(system.string))

92 {

93 trace.warn(level.tostring(), spaces(level) + "" + vs.tostring() + "");

94 }

95 else if (vs.gettype().isprimitive)

96 {

97 trace.warn(level.tostring(), spaces(level) + vs.tostring());

98 }

99 else

100 {

101 trace.warn(level.tostring(), spaces(level) + vs.gettype().tostring());

102 }

103 }

104 private void parseviewstate(triplet vs, int level)

105 {

106 parseviewstate(vs.first, level + 1);

107 parseviewstate(vs.second, level + 1);

108 parseviewstate(vs.third, level + 1);

109 }

110 private void parseviewstate(pair vs, int level)

111 {

112 parseviewstate(vs.first, level + 1);

113 parseviewstate(vs.second, level + 1);

114 }

115 private void parseviewstate(ienumerable vs, int level)

116 {

117 foreach (object item in vs)

118 {

119 parseviewstate(item, level + 1);

120 }

121 }

122

123 // 得到指定数目的空白

124 private string spaces(int count)

125 {

126 string spaces = "";

127 for (int index = 0; index < count; index++)

128 {

129 spaces += " ";

130 }

131 return spaces;

132 }

133 }

134}

135

译注:上面代码由本人测试后加上了 vs.net 自动生成的其他部分代码,为方便大家试验。

赞(0)
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com 特别注意:本站所有转载文章言论不代表本站观点! 本站所提供的图片等素材,版权归原作者所有,如需使用,请与原作者联系。未经允许不得转载:IDC资讯中心 » ViewState 剖析(翻译兼笔记)-ASP教程,ASP应用
分享到: 更多 (0)

相关推荐

  • 暂无文章