Сжатие и распаковка данных в памяти
Прежде всего, нам нужен способ сжатия и распаковки массива байтов в памяти. Я собрал этот простой статический класс, который предоставляет два метода: Compress и Decompress. Два доступных класса, GZipStream и DeflateStream, согласно MSDN, используют один и тот же алгоритм, поэтому не имеет значения, какой из них вы выберете.
Код, приведенный ниже, действительно прост и не нуждается в дополнительных пояснениях:
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 и поместить его в каталог App_Code вашего приложения ASP.NET, убедившись, что он содержится в надлежащем настраиваемом пространстве имен (если вы не укажете пространство имен, класс будет быть доступным во встроенном пространстве имен ASP).
Сжатие ViewState
Теперь мы можем сжать ViewState страницы. Чтобы сделать это, мы должны переопределить два метода LoadPageStateFromPersistenceMedium и SavePageStateToPersistenceMedium. Код просто использует дополнительное скрытое поле __VSTATE для хранения сжатого ViewState. Как вы можете видеть, просматривая HTML-код страницы, поле __VIEWSTATE пустое, а наше поле __VSTATE содержит сжатый ViewState, закодированный в Base64. Давайте посмотрим код.
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 выполняет задачи сериализации и десериализации.
Вы также можете создать новый класс, например, CompressedPage, унаследованный от System.Web.UI.Page, в котором вы переопределяете два метода, а затем наследуете свою страницу от этого класса, например MyPage: CompressedPage. Просто помните, что .NET имеет только одно наследование, и, следуя этим путем, вы «тратите» свой единственный шанс наследования на использование сжатия ViewState. С другой стороны, переопределение двух методов в каждом классе - пустая трата времени, поэтому вы должны выбрать способ, который наилучшим образом соответствует вашим потребностям.
Вышесказанное было впервые опубликовано Дарио Солерой на codeproject.
http://www.codeproject.com/Articles/14733/ViewState-Compression