有人说类似gridview datalist这样的控件最好不要用在高并发,IO大的网站中
企业应用中为了快速开发到可以用一用
因为这是一类"沉重"的组件
我们姑且不谈这种看法的正确性(我个人觉得有道理)
只谈它为什么笨重:
因为这些控件给页面带来了大量的
viewstate
<input type="hidden" name="____VIEWSTATE" id="____VIEWSTATE" value=
这就是页面状态
一个页面里可能存在两种状态
控件状态,视图状态
page类是在
LoadPageStateFromPersistenceMedium()
SavePageStateToPersistenceMedium()
存取页面状态的
这两个方法都是可以重写的
他们也可以把状态信息存储在别的媒介中
我们这里通过重写PageStatePersister属性
来实现自己的状态存取逻辑
我们为了压缩viewstate里的数据,必须先实现一个工具类:如下
Code
using System;
using System.IO;
using System.IO.Compression;
using System.Web.UI;
/// <summary>
///GZipCompress 的摘要说明
/// </summary>
public class GZipCompress
{
//LosFormatter序列化web窗体页的视图状态
private static LosFormatter _formater = new LosFormatter();
public GZipCompress()
{}
//带压缩功能的序列化
public static string Compress(object state)
{
StringWriter writer = new StringWriter();
//序列化状态
_formater.Serialize(writer, state);
//取得序列化结果
string stateString = writer.ToString();
writer.Close();
//将字符串转换成八位无符号整数数组
byte[] buffer = Convert.FromBase64String(stateString);
MemoryStream ms = new MemoryStream();
//搞一个压缩流出来,将流保持为打开的状态
GZipStream zipStream = new GZipStream(ms, CompressionMode.Compress, true);
zipStream.Write(buffer, 0, buffer.Length);
zipStream.Close();
buffer = new byte[ms.Length];
//获取或设置流中的当前位置
ms.Position = 0;
ms.Read(buffer, 0, buffer.Length);
ms.Close();
//将压缩结果转成字符串,便于保存在页面中
stateString = Convert.ToBase64String(buffer);
return stateString;
}
public static object Decompress(string stateString)
{
byte[] buffer = Convert.FromBase64String(stateString);
MemoryStream ms = new MemoryStream(buffer);
GZipStream zipStream = new GZipStream(ms, CompressionMode.Decompress);
MemoryStream msReader = new MemoryStream();
buffer = new byte[0x1000];//开辟0x1000个字节空间16*16*16=4K
while (true)
{
int read = zipStream.Read(buffer, 0, buffer.Length);
if (read <= 0)
{ break; }
msReader.Write(buffer, 0, read);
}
zipStream.Close();
ms.Close();
msReader.Position = 0;
buffer = msReader.ToArray();
stateString = Convert.ToBase64String(buffer);
return _formater.Deserialize(stateString);
}
}
using System;
using System.IO;
using System.IO.Compression;
using System.Web.UI;
/// <summary>
///GZipCompress 的摘要说明
/// </summary>
public class GZipCompress
{
//LosFormatter序列化web窗体页的视图状态
private static LosFormatter _formater = new LosFormatter();
public GZipCompress()
{}
//带压缩功能的序列化
public static string Compress(object state)
{
StringWriter writer = new StringWriter();
//序列化状态
_formater.Serialize(writer, state);
//取得序列化结果
string stateString = writer.ToString();
writer.Close();
//将字符串转换成八位无符号整数数组
byte[] buffer = Convert.FromBase64String(stateString);
MemoryStream ms = new MemoryStream();
//搞一个压缩流出来,将流保持为打开的状态
GZipStream zipStream = new GZipStream(ms, CompressionMode.Compress, true);
zipStream.Write(buffer, 0, buffer.Length);
zipStream.Close();
buffer = new byte[ms.Length];
//获取或设置流中的当前位置
ms.Position = 0;
ms.Read(buffer, 0, buffer.Length);
ms.Close();
//将压缩结果转成字符串,便于保存在页面中
stateString = Convert.ToBase64String(buffer);
return stateString;
}
public static object Decompress(string stateString)
{
byte[] buffer = Convert.FromBase64String(stateString);
MemoryStream ms = new MemoryStream(buffer);
GZipStream zipStream = new GZipStream(ms, CompressionMode.Decompress);
MemoryStream msReader = new MemoryStream();
buffer = new byte[0x1000];//开辟0x1000个字节空间16*16*16=4K
while (true)
{
int read = zipStream.Read(buffer, 0, buffer.Length);
if (read <= 0)
{ break; }
msReader.Write(buffer, 0, read);
}
zipStream.Close();
ms.Close();
msReader.Position = 0;
buffer = msReader.ToArray();
stateString = Convert.ToBase64String(buffer);
return _formater.Deserialize(stateString);
}
}
下面重写PageStatePersister来实现自定义的页面状态存取
Code
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.IO;
using System.IO.Compression;
/// <summary>
///PageStatePersister 的摘要说明
/// </summary>
public class CompressPageStatePersister:PageStatePersister
{
private const string STATEKEY = "____VIEWSTATE";
//调用基类构造函数
public CompressPageStatePersister(Page page) : base(page) { }
//加载页面状态
public override void Load()
{
//取得保存在客户端的状态内容
string postbackstate = Page.Request.Form[STATEKEY];
if (!string.IsNullOrEmpty(postbackstate))
{
//解压,反序列化
//asp.net的viewstate包括控件状态和视图状态
//存储两个相关对象
Pair statePair = (Pair)GZipCompress.Decompress(postbackstate);
if (Page.EnableViewState)
{
ViewState = null;
}
else
{
ViewState = statePair.First;
}
ControlState = statePair.Second;
}
}
//保存页面状态
public override void Save()
{
if (!Page.EnableViewState)
{
ViewState = null;
}
if (ViewState != null || ControlState != null)
{
string stateString;
Pair statePair = new Pair(ViewState, ControlState);
//序列化,压缩
stateString = GZipCompress.Compress(statePair);
//把页面状态注册到页面上
Page.ClientScript.RegisterHiddenField(STATEKEY, stateString);
}
}
}
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.IO;
using System.IO.Compression;
/// <summary>
///PageStatePersister 的摘要说明
/// </summary>
public class CompressPageStatePersister:PageStatePersister
{
private const string STATEKEY = "____VIEWSTATE";
//调用基类构造函数
public CompressPageStatePersister(Page page) : base(page) { }
//加载页面状态
public override void Load()
{
//取得保存在客户端的状态内容
string postbackstate = Page.Request.Form[STATEKEY];
if (!string.IsNullOrEmpty(postbackstate))
{
//解压,反序列化
//asp.net的viewstate包括控件状态和视图状态
//存储两个相关对象
Pair statePair = (Pair)GZipCompress.Decompress(postbackstate);
if (Page.EnableViewState)
{
ViewState = null;
}
else
{
ViewState = statePair.First;
}
ControlState = statePair.Second;
}
}
//保存页面状态
public override void Save()
{
if (!Page.EnableViewState)
{
ViewState = null;
}
if (ViewState != null || ControlState != null)
{
string stateString;
Pair statePair = new Pair(ViewState, ControlState);
//序列化,压缩
stateString = GZipCompress.Compress(statePair);
//把页面状态注册到页面上
Page.ClientScript.RegisterHiddenField(STATEKEY, stateString);
}
}
}
项目的webconfig文件
Code
<?xml version="1.0"?>
<configuration>
<appSettings/>
<connectionStrings>
<add name="AntMallConnectionString" connectionString="Data Source=192.168.1.186;Initial Catalog=AntMall;Integrated Security=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
<system.web>
<compilation debug="true"></compilation>
<authentication mode="Forms"/>
</system.web>
</configuration>
<?xml version="1.0"?>
<configuration>
<appSettings/>
<connectionStrings>
<add name="AntMallConnectionString" connectionString="Data Source=192.168.1.186;Initial Catalog=AntMall;Integrated Security=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
<system.web>
<compilation debug="true"></compilation>
<authentication mode="Forms"/>
</system.web>
</configuration>
用来测试的一个页面
Code
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>无标题页</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:GridView ID="GridView1" runat="server" AllowPaging="True"
DataSourceID="SqlDataSource1" AutoGenerateColumns="False">
<Columns>
<asp:BoundField DataField="title" HeaderText="title" SortExpression="title" />
<asp:BoundField DataField="memo" HeaderText="memo" SortExpression="memo" />
<asp:BoundField DataField="fullPrice" HeaderText="fullPrice"
SortExpression="fullPrice" />
<asp:BoundField DataField="defaultPic" HeaderText="defaultPic"
SortExpression="defaultPic" />
<asp:BoundField DataField="inputTime" HeaderText="inputTime"
SortExpression="inputTime" />
</Columns>
</asp:GridView>
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:AntMallConnectionString %>"
SelectCommand="SELECT [fullPrice], [inputTime], [memo], [title], [defaultPic] FROM [Product]">
</asp:SqlDataSource>
</div>
</form>
</body>
</html>
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>无标题页</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:GridView ID="GridView1" runat="server" AllowPaging="True"
DataSourceID="SqlDataSource1" AutoGenerateColumns="False">
<Columns>
<asp:BoundField DataField="title" HeaderText="title" SortExpression="title" />
<asp:BoundField DataField="memo" HeaderText="memo" SortExpression="memo" />
<asp:BoundField DataField="fullPrice" HeaderText="fullPrice"
SortExpression="fullPrice" />
<asp:BoundField DataField="defaultPic" HeaderText="defaultPic"
SortExpression="defaultPic" />
<asp:BoundField DataField="inputTime" HeaderText="inputTime"
SortExpression="inputTime" />
</Columns>
</asp:GridView>
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:AntMallConnectionString %>"
SelectCommand="SELECT [fullPrice], [inputTime], [memo], [title], [defaultPic] FROM [Product]">
</asp:SqlDataSource>
</div>
</form>
</body>
</html>
用来测试的页面的cs文件
注意里面重写了PageStatePersister
Code
using System;
using System.Configuration;
using System.Data;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
public partial class _Default : System.Web.UI.Page
{
#region 重写PageStatePersister定制页面状态持久化行为
CompressPageStatePersister _pageStatePersister = null;
protected override PageStatePersister PageStatePersister
{
get
{
if (_pageStatePersister == null)
{
_pageStatePersister = new CompressPageStatePersister(this);
}
return _pageStatePersister;
}
}
#endregion
protected void Page_Load(object sender, EventArgs e)
{
}
}
using System;
using System.Configuration;
using System.Data;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
public partial class _Default : System.Web.UI.Page
{
#region 重写PageStatePersister定制页面状态持久化行为
CompressPageStatePersister _pageStatePersister = null;
protected override PageStatePersister PageStatePersister
{
get
{
if (_pageStatePersister == null)
{
_pageStatePersister = new CompressPageStatePersister(this);
}
return _pageStatePersister;
}
}
#endregion
protected void Page_Load(object sender, EventArgs e)
{
}
}
实验做完
大家运行一下就知道
定制出来的viewstate比自动生成的要小很多
最后评价一句
传输给客户的东西是少了许多
但是服务器的CPU要做的事情也多了
用与不用还要自己权衡