所以基本上我正在尝试针对手机进行优化的网站(这包括几乎所有支持浏览器的手机)由于网站的性质,我希望它尽快加载。此时,我认为页面的大小约为30k左右。
现在我正在使用viewstate,主要用于datagrids之类的东西,而不是自己“保存”任何字段。
我已经看到很多这样的例子,例如(I swear not my blog),但是没有涉及到3.5,这让我想知道从那以后没有任何改变或压缩视图状态已经失宠了。
问题是,我是否应该尝试压缩视图状态,还是有更好的解决方案?
答案 0 :(得分:4)
我正在使用viewstate,主要用于datagrids之类的东西,而不是自己“保存”任何字段。
这是我最担心的网格。您自己保存的字段往往是简单的变量,如数据库ID或用户名。这些问题不会引起太多问题,因为它们很小。整个网格可能是很多数据,而这就是你遇到麻烦的地方。
请记住,用户必须将viewstate的内容从浏览器上传到服务器,然后在每次回发时将其下载回来。如果你有一个100Mbit的连接到web服务器 - 就像一个公司的局域网,webforms往往更受欢迎 - 那么viewstate是伟大的。但是对于手机浏览器,许多用户可能相当于拨号,甚至更糟糕:按字节付费。在这种情况下,我会尝试尽可能地关闭它,并且只在必要时启用它。
答案 1 :(得分:2)
压缩和解压缩内存中的数据
首先,我们需要一种压缩和解压缩内存中字节数组的方法。我将这个简单的静态类放在一起,它暴露了两种方法:压缩和解压缩。根据MSDN,两个可用的类GZipStream和DeflateStream使用相同的算法,因此与您选择的算法无关。
以下代码非常简单,无需进一步说明:
using System.IO;
using System.IO.Compression;
public static class Compressor {
public static byte[] Compress(byte[] data) {
MemoryStream output = new MemoryStream();
GZipStream gzip = new GZipStream(output,
CompressionMode.Compress, true);
gzip.Write(data, 0, data.Length);
gzip.Close();
return output.ToArray();
}
public static byte[] Decompress(byte[] data) {
MemoryStream input = new MemoryStream();
input.Write(data, 0, data.Length);
input.Position = 0;
GZipStream gzip = new GZipStream(input,
CompressionMode.Decompress, true);
MemoryStream output = new MemoryStream();
byte[] buff = new byte[64];
int read = -1;
read = gzip.Read(buff, 0, buff.Length);
while(read > 0) {
output.Write(buff, 0, read);
read = gzip.Read(buff, 0, buff.Length);
}
gzip.Close();
return output.ToArray();
}
}
您需要将此类保存在.cs文件中并将其放在ASP.NET应用程序的App_Code目录中,确保它包含在正确的自定义命名空间中(如果您未指定任何命名空间,则该类将在内置的ASP命名空间中可用。)
压缩ViewState
现在,我们可以实际压缩页面的ViewState。为此,我们必须覆盖LoadPageStateFromPersistenceMedium和SavePageStateToPersistenceMedium这两个方法。代码只是使用一个额外的隐藏字段__VSTATE来存储压缩的ViewState。如您所见,通过查看页面的HTML,__ OutlookSTATE字段为空,而__VSTATE字段包含以Base64编码的压缩ViewState。我们来看看代码。
public partial class MyPage : System.Web.UI.Page {
protected override object LoadPageStateFromPersistenceMedium() {
string viewState = Request.Form["__VSTATE"];
byte[] bytes = Convert.FromBase64String(viewState);
bytes = Compressor.Decompress(bytes);
LosFormatter formatter = new LosFormatter();
return formatter.Deserialize(Convert.ToBase64String(bytes));
}
protected override void SavePageStateToPersistenceMedium(object viewState) {
LosFormatter formatter = new LosFormatter();
StringWriter writer = new StringWriter();
formatter.Serialize(writer, viewState);
string viewStateString = writer.ToString();
byte[] bytes = Convert.FromBase64String(viewStateString);
bytes = Compressor.Compress(bytes);
ClientScript.RegisterHiddenField("__VSTATE", Convert.ToBase64String(bytes));
}
// The rest of your code here...
}
在第一种方法中,我们只是从Base64解码,解压缩和反序列化__VSTATE的内容,并将其返回到运行时。在第二种方法中,我们执行相反的操作:在Base64中进行序列化,压缩和编码。然后将Base64字符串保存到__VSTATE隐藏字段中。 LosFormatter对象执行序列化和反序列化任务。
您可能还想创建一个新类,例如,继承自System.Web.UI.Page的CompressedPage,您可以在其中覆盖这两个方法,然后从该类继承您的页面,例如MyPage:CompressedPage。请记住,.NET只有单一继承,通过这种方式,您可以“花费”唯一的继承机会来使用ViewState压缩。另一方面,在每个班级中重写这两种方法都是浪费时间,因此您必须选择最适合您需求的方式。
以上内容首先由Dario Solera在codeproject上发布。 http://www.codeproject.com/Articles/14733/ViewState-Compression
答案 2 :(得分:1)
我不认为它已经失宠,只是在2.0中保存视图状态应该与在3.5中保存视图状态相同。减少viewstate的最佳方法是不使用它,但这并不总是可行的。
在这些情况下,您应该尝试权衡带宽与服务器上所需的额外处理时间之间的权衡。知道它是否值得的唯一方法是做它并测量影响。
修改强>
我看到的另一个选项是在服务器上保存视图状态。它可以保存在内存,数据库或磁盘中。根据您的环境要求。这将是最大的带宽节省。
答案 3 :(得分:0)
拥有ViewState与快速加载网页相反。你为什么需要ViewState?尽可能少地重新考虑您的设计和使用。我会将Session数据的粗略部分放在服务器和/或数据库上,直到有理由在ViewState中保留一些数据。
答案 4 :(得分:0)
视图状态的压缩只能将其减少50%左右。我向前走了几步并使用了ViewState替换技术,其中ViewState被页面上的GUID替换。实际的ViewState数据保存在服务器本身的数据库中,客户端(浏览器)获取和提交的数据只是一个62字节的令牌。它将大型ViewStates减少了200-300KB到62个字节。
这里我已经用代码编写了如何做到这一点.. http://ashishnangla.com/2011/07/21/reducing-size-of-viewstate-in-asp-net-webforms-by-writing-a-custom-viewstate-provider-pagestatepersister-part-12/