ASP.NET: сжатие ViewState
Каковы последние и лучшие способы сжатия содержимого ASP.NET ViewState?
Как насчет производительности этого? Стоит ли держать страницы быстрыми и минимизировать трафик данных?
Как я могу сделать:
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE"
value="/wEPDwUKMTM4Mjc3NDEyOWQYAQUeX19Db250cm9sc1JlcXVpcmVQb3N0QmFja0tleV9fFgkFLGN0b
DAwJENvbnRlbnRQbGFjZUhvbGRlcl9NYWluQ29udGVudCRSYWRCdXQxBSxjdGwwMCRDb250ZW50UGxhY2VIb
2xkZXJfTWFpbkNvbnRlbnQkUmFkQnV0MQUsY3RsMDAkQ29udGVudFBsYWNlSG9sZGVyX01haW5Db250ZW50J
FJhZEJ1dDIFLGN0bDAwJENvbnRlbnRQbGFjZUhvbGRlcl9NYWluQ29udGVudCRSYWRCdXQyBSxjdGwwMCRDb
250ZW50UGxhY2VIb2xkZXJfTWFpbkNvbnRlbnQkUmFkQnV0MwUsY3RsMDAkQ29udGVudFBsYWNlSG9sZGVyX
01haW5Db250ZW50JFJhZEJ1dDQFLGN0bDAwJENvbnRlbnRQbGFjZUhvbGRlcl9NYWluQ29udGVudCRSYWRCd
XQ0BSxjdGwwMCRDb250ZW50UGxhY2VIb2xkZXJfTWFpbkNvbnRlbnQkUmFkQnV0NQUsY3RsMDAkQ29udGVud
FBsYWNlSG9sZGVyX01haW5Db250ZW50JFJhZEJ1dDXz21BS0eJ7991pzjjj4VXbs2fGBw==" />
Что-то вроде этого:
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE"
value="/wEPDwUKMTM4Mjc3N==" />
8 ответов
Опять же, после некоторого исследования этого я обобщил свои выводы в блоге о сжатии состояния просмотра.
Чтобы сохранить сжатое состояние просмотра, я сделал следующее:
protected override void SavePageStateToPersistenceMedium(object state) {
SaveCompressedPageState(state);
}
private void SaveCompressedPageState(object state) {
byte[] viewStateBytes;
using(MemoryStream stream = new MemoryStream()) {
ObjectStateFormatter formatter = new ObjectStateFormatter();
formatter.Serialize(stream, state);
viewStateBytes = stream.ToArray();
}
byte[] compressed = CompressionHelper.Compress(viewStateBytes);
string compressedBase64 = Convert.ToBase64String(compressed);
ClientScript.RegisterHiddenField(ViewStateFieldName, compressedBase64);
}
И для загрузочной части этот код заставил меня работать:
protected override object LoadPageStateFromPersistenceMedium() {
return LoadCompressedPageState();
}
private object LoadCompressedPageState() {
string viewState = Request.Form[ViewStateFieldName];
if(string.IsNullOrEmpty(viewState)) {
return string.Empty;
}
byte[] decompressed = CompressionHelper.Decompress(viewState);
string decompressedBase64 = Convert.ToBase64String(decompressed);
ObjectStateFormatter formatter = new ObjectStateFormatter();
return formatter.Deserialize(decompressedBase64);
}
Простой ответ может быть не тем, что вы хотите услышать. Слишком часто элементы управления на странице имеют состояние просмотра по умолчанию, когда им это действительно не нужно. Хорошей идеей будет отключить viewstate до тех пор, пока вы не узнаете, что он вам понадобится, и включать его только для (надеюсь) нескольких случаев, когда вы действительно хотите сохранить состояние просмотра.
- Избегайте использования ViewState
- Используйте сжатие на сервере IIS.
- Вы можете подключить что-то, что сожмет состояние просмотра на страницу и из нее, выполнив что-то вроде:
public abstract class PageBase : System.Web.UI.Page
{
private ObjectStateFormatter _formatter = new ObjectStateFormatter();
private static byte[] Compress( byte[] data )
{
var compressedData = new MemoryStream();
var compressStream = new GZipStream(output, CompressionMode.Compress, true);
compressStream.Write(data, 0, data.Length);
compressStream.Close();
return compressedData.ToArray();
}
private static byte[] Uncompress( byte[] data )
{
var compressedData = new MemoryStream();
input.Write(compressedData, 0, compressedData.Length);
input.Position = 0;
var compressStream = new GZipStream(compressedData, CompressionMode.Decompress, true);
var uncompressedData = new MemoryStream();
var buffer = new byte[64];
var read = compressStream.Read(buffer, 0, buffer.Length);
while (read > 0)
{
uncompressedData.Write(buffer, 0, read);
read = compressStream.Read(buffer, 0, buffer.Length);
}
compressStream.Close();
return uncompressedData.ToArray();
}
protected override void SavePageStateToPersistenceMedium(object viewState)
{
var ms = new MemoryStream();
_formatter.Serialize(ms, viewState);
var viewStateBytes = ms.ToArray();
ClientScript.RegisterHiddenField("__COMPRESSED_VIEWSTATE"
, Convert.ToBase64String( Compress(viewStateArray)) );
}
protected override object LoadPageStateFromPersistenceMedium()
{
var compressedViewState = Request.Form["__COMPRESSED_VIEWSTATE"];
var bytes = Uncompress( Convert.FromBase64String( compressedViewState ) );
return _formatter.Deserialize( Convert.ToBase64String( bytes ) );
}
}
Я понимаю, что это старый поток, но мы уже давно используем HttpModule RadCompression от Telerik, и он невероятно хорошо работает при сжатии ответов ViewState, AJAX и Web-сервисов. Вы также можете обманывать и сохранять ViewState в сеансе - хорошо для сайтов с низким трафиком.
Это XML-визуализация вашего опубликованного состояния просмотра:
<viewstate>
<Pair>
<Pair>
<String>1382774129</String>
</Pair>
</Pair>
</viewstate>
<controlstate>
<HybridDictionary>
<DictionaryEntry>
<String>__ControlsRequirePostBackKey__</String>
<ArrayList>
<String>ctl00$ContentPlaceHolder_MainContent$RadBut1</String>
<String>ctl00$ContentPlaceHolder_MainContent$RadBut1</String>
<String>ctl00$ContentPlaceHolder_MainContent$RadBut2</String>
<String>ctl00$ContentPlaceHolder_MainContent$RadBut2</String>
<String>ctl00$ContentPlaceHolder_MainContent$RadBut3</String>
<String>ctl00$ContentPlaceHolder_MainContent$RadBut4</String>
<String>ctl00$ContentPlaceHolder_MainContent$RadBut4</String>
<String>ctl00$ContentPlaceHolder_MainContent$RadBut5</String>
<String>ctl00$ContentPlaceHolder_MainContent$RadBut5</String>
</ArrayList>
</DictionaryEntry>
</HybridDictionary>
</controlstate>
В основном только несколько радиокнопок, которые хотели бы знать об их существовании. (браузеры не отправляют <input type="radio">
поле с постданными, если оно не отмечено). Это уже довольно минимально.
Скорее всего, его можно сжать, подключив методы загрузки / сохранения или HTTP-модули, но это может быть не очень практично и не нужно.
В случае, если viewstate намного больше в вашем реальном приложении, вообще избегайте попадания объектов в viewstate. Это может быть достигнуто путем инициализации элементов управления в OnInit()
или же Page_Init()
методы вместо стандартных Page_Load()
,
Обоснование этого можно найти по адресу http://weblogs.asp.net/infinitiesloop/archive/2006/08/03/Truly-Understanding-Viewstate.aspx и http://msdn.microsoft.com/en-us/library/ms972976.aspx
Краткое резюме:
- ViewState - это просто хранилище для почти всех свойств элемента управления, включая значения по умолчанию.
- После того, как значения по умолчанию установлены
OnInit()
,TrackViewState()
метод будет вызван. - Любые последующие изменения (например,
Page_Load()
) или обработчик событий, будет отслеживаться и отправляться клиенту. Таким образом, эти элементы управления могут восстановить свое состояние при следующем запросе. - Вместо того чтобы полагаться на структуру для восстановления объектов, восстановите объекты в
OnInit()
при необходимости. (например, заселение вариантовDropDownList
из базы данных).
Одно исключение:
Если элемент управления динамически добавляется в дерево элементов управления, он воспроизводит данные. Их OnInit()
Метод может быть запущен в более поздний момент, в результате чего эти свойства в конечном итоге окажутся в состоянии просмотра. Если инициализация элемента управления не может произойти в OnInit()
, настройка EnableViewState="false"
может быть использован в качестве обходного пути.
Каждый раз, когда мое состояние просмотра неожиданно увеличивается, я использую приложение ViewState Decoder 2.2, чтобы выяснить, что же произошло в этом состоянии. Часто это не нужно для данных, чтобы быть там.
И последнее слово:
Представление не используется для переполнения форм! Эти значения уже отправлены с постданными.
Seb, ViewState уже сжат... это то, что вы видите... сжатая версия ваших элементов управления. Если вы хотите меньше накладных расходов, то не используйте viewstate:)
Использование Viewstate должно быть сведено к минимуму!
Сжатие состояния просмотра в некоторых случаях дает сбой: - Если вы используете панель обновления на странице, не используйте режим сжатия. - Если каким-то образом вы изменяете состояние просмотра в результате кода ICallBack, не используйте режим сжатия, так как это не будет отражать правильное состояние просмотра при обратной передаче.
Лучший способ минимизировать состояние просмотра - просто не использовать его. Это заставит вас заняться дополнительным рабочим программированием (повторное заполнение контрольных значений и т. Д. После обратной отправки, но это сэкономит вам объем информации, которую вы отправляете в браузер). Вы не можете вмешиваться в это.
Вот ссылка на состояние просмотра на MSDN:
http://msdn.microsoft.com/en-us/library/ms972976.aspx
Вот ссылка, описывающая некоторые лучшие практики:
http://mnairooz.blogspot.com/2007/01/aspnet-20-viewstate-and-good-practices.html
И один об отключении ViewState:
http://www.codeproject.com/KB/aspnet/ASPNET_Best_Practices.aspx