我们都知道表单提交时,input,textbox,select等表单元素,最终会以名值对的样子提交给服务器(当form中的属性method=“get”时可以清晰看到),但是如果是DIV,或者Span怎么办?
解决问题的办法是,通过js把div或者span的值放到一个隐藏表单元素中(<input type="hidden" name="aaa" value="" />),该隐藏表单元素一方面不会显示在页面上,提交时会与其他表单元素一起提交,这样在服务器端就可以接收到。
ViewState的作用还有一点就是持久化保存数据。持久化保存数据的方法有很多种,可以放在硬盘上文件中,放在Cookie中,可以放在session中,或者放在页面本身。
网络上有些人介绍了怎么修改viewstate保存方式,从而保存在硬盘文件中,方法这里不介绍了,自己去找。
放在硬盘上的问题在于,读写慢。特别是大量的读写,一方面慢,再者会对硬盘造成损害,或产生大量磁盘碎片。
放在客户端Cookie的问题在于,不知道有多少人禁用了cookie,或者采用所谓的安全浏览器来屏蔽cookie。
放在服务器端Session的问题在于,session肯定要占用内存,虽然对于服务器,它是安全的,但小数据还能接受,无法存储大量的数据,特别是服务器本身访问量很大的时候。
ViewState,也不适合存储大量的数据,否则一个网页的文件大小会变得非常大,下载的时候时间长,提交的时候时间也长。
微软的.net平台用了name="__VIEWSTATE"的隐藏表单元素,从而可以创建交互性非常强的交互页面,只不过value值是经过序列化处理的后的值,而不是明文存放,因而杜绝了一些“低手”对于viewState乱改的情况,然而在“高手”面前,它与明文没有任何区别。
下面贴一段代码,别人写的ViewState解码分析器,当然从这里你也应该明白,不要把重要的东西放在viewState里,特别是密码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Web.UI;
using System.Collections;
using System.Xml;
using System.Collections.Specialized;
using System.Text.RegularExpressions;
namespace ViewState解码分析器
{
public partial class Form1 : Form
{
TextBox textbox = null;
public Form1()
{
InitializeComponent();
}
private void txtViewState_Leave(object sender, EventArgs e)
{
textbox = (TextBox)sender;
}
private void splitContainer1_SplitterMoved(object sender, SplitterEventArgs e)
{
if (textbox == null)
{
textbox = txtViewState;
}
textbox.Focus();
}
#region 对输入的ViewState字符串进行解码分析 + private void txtDecoder_Click(object sender, EventArgs e)
private void txtDecoder_Click(object sender, EventArgs e)
{
XmlDocument document = null;
string vs = get__ViewCodeString(txtViewState.Text.Trim());//获取待解码的ViewState字符串
if (string.IsNullOrEmpty(vs)) return;
byte[] buff = Encoding.UTF8.GetBytes(vs);
Stream stream = new MemoryStream(buff);
try
{
LosFormatter lf = new LosFormatter();
object allViewState = lf.Deserialize(stream);//解码// LosFormatter 还有一些重写方法,比如可以直接lf.Deserialize(vs);
XmlDocument dom = ViewStateXmlBuilder.BuildXml(allViewState);
StringBuilder sb = new StringBuilder();
using (StringWriter writer = new StringWriter(sb))
{
dom.Save(writer);
}
txtResult.Text = sb.ToString();
}
catch (Exception er)
{
MessageBox.Show(er.Message, "解析错误", MessageBoxButtons.OK, MessageBoxIcon.Stop);
}
}
#endregion
#region 简化显示ViewState解码后的内容 + private void btnSimple_Click(object sender, EventArgs e)
private void btnSimple_Click(object sender, EventArgs e)
{
string s = Regex.Replace(txtResult.Text, "<[^>]+>", "");
txtResult.Text = Regex.Replace(s, @"(?m)^\s+{1}quot;, "\r\n");
}
#endregion
#region 窗体加载时设置Panel2的最小宽度 + private void Form1_Load(object sender, EventArgs e)
private void Form1_Load(object sender, EventArgs e)
{
splitContainer1.Panel2MinSize = 430;//设置Panel2的最小宽度
}
#endregion
#region 获取正确的待解码的ViewState + private string get__ViewCodeString(string s)
/// <summary>
/// 获取正确的待解码的ViewState
/// </summary>
/// <param name="s">可能含有“引号外多余内容”的ViewState串</param>
/// <returns></returns>
private string get__ViewCodeString(string s)
{
int p1 = s.IndexOf('"');
if (p1 >= 0)//若不含双引号,则取整串内容
{
int p2 = s.IndexOf('"', p1 + 1);
if (p2 > 0)//有一对双引号,则取双引号内部的东东
{
s = s.Substring(p1 + 1, p2 - p1 - 1);
}
else//若仅有一个双引号,则取引号两侧较长的字符串
{
string s1 = s.Substring(0, p1).Trim();
string s2 = s.Substring(p1 + 1).Trim();
s = s1.Length > s2.Length ? s1 : s2;
}
}
return s;
}
#endregion
}
#region 类ViewStateXmlBuilder,创建ViewState XMLDocument
public class ViewStateXmlBuilder
{
public static XmlDocument BuildXml(object tree)
{
XmlDocument dom = new XmlDocument();
dom.AppendChild(dom.CreateElement("ViewState"));
BuildElement(dom, dom.DocumentElement, tree);
return dom;
}
private static void BuildElement(XmlDocument dom, XmlElement elem, object treeNode)
{
if (treeNode != null)
{
XmlElement element;
Type type = treeNode.GetType();
if (type == typeof(Pair))
{
element = dom.CreateElement(GetShortTypename(treeNode));
elem.AppendChild(element);
BuildElement(dom, element, ((Pair)treeNode).First);
BuildElement(dom, element, ((Pair)treeNode).Second);
}
else if (type == typeof(Triplet))
{
element = dom.CreateElement(GetShortTypename(treeNode));
elem.AppendChild(element);
BuildElement(dom, element, ((Triplet)treeNode).First);
BuildElement(dom, element, ((Triplet)treeNode).Second);
BuildElement(dom, element, ((Triplet)treeNode).Third);
}
else if (type == typeof(ArrayList))
{
element = dom.CreateElement(GetShortTypename(treeNode));
elem.AppendChild(element);
foreach (object obj in (ArrayList)treeNode)
{
BuildElement(dom, element, obj);
}
}
else if (treeNode is Array)
{
element = dom.CreateElement("Array");
elem.AppendChild(element);
foreach (object obj in (Array)treeNode)
{
BuildElement(dom, element, obj);
}
}
else if (treeNode is HybridDictionary)
{
element = dom.CreateElement(GetShortTypename(treeNode));
dom.DocumentElement.AppendChild(element);
foreach (object obj in (HybridDictionary)treeNode)
{
BuildElement(dom, element, obj);
}
}
else if (treeNode is DictionaryEntry)
{
element = dom.CreateElement(GetShortTypename(treeNode));
elem.AppendChild(element);
DictionaryEntry entry = (DictionaryEntry)treeNode;
BuildElement(dom, element, entry.Key);
BuildElement(dom, element, entry.Value);
}
else
{
element = dom.CreateElement(GetShortTypename(treeNode));
if (type == typeof(IndexedString))
{
element.InnerText = ((IndexedString)treeNode).Value;
}
else
{
element.InnerText = treeNode.ToString();
}
elem.AppendChild(element);
}
}
}
private static string GetShortTypename(object obj)
{
string str = obj.GetType().ToString();
return str.Substring(str.LastIndexOf(".") + 1);
}
}
#endregion
}
···
···