Опубликован: 30.01.2013 | Уровень: для всех | Доступ: платный
Лекция 3:

Анатомия приложений ASP.NET

Сохранение состояния

Одной из наиболее важных проблем при разработке веб-приложений является специфика взаимодействия клиента и сервера по протоколу HTTP. Как известно, взаимодействие клиента и сервера по протоколу HTTP происходит в режиме "запрос-ответ", при этом сервер удаляет все данные, специфичные для этого взаимодействия после того, как отправит ответ. Веб-сервер вынужден делать подобную очистку из-за того, что он может обслуживать большое количество клиентов.

Однако, несмотря на это в большинстве случаев веб-приложению требуется сохранять состояние приложения между выполняющимися запросами. Например, приложению может потребоваться сохранить имя пользователя и пароль для дальнейшего взаимодействия с сайтом, или сохранить состояние формы для ее корректной обработки в будущем. Эту специфику учитывает платформа Microsoft ASP.NET и разработчику не требуется изобретать собственных механизмов по сохранению состояния.

Платформа ASP.NET содержит целый ряд инструментов, которые позволяют сохранять состояние между HTTP-запросами:

  • строка запроса (QueryString);
  • состояние вида (ViewState);
  • состояние сенаса (Session);
  • состояние приложения (Application);
  • профили;
  • и другие.

Как видно, доступно множество способов сохранения состояния. Они отличаются друг от друга контекстом сохранения состояния или, иначе говоря, временем жизни данных, сохраненных между запросами.

Строка запроса (QueryString) позволяет сохранять состояние при обращении к текущей или внешней странице сайта. При этом значение состояние передается в строке запроса в качестве параметра GET. Например, такой запрос может выглядеть следующим образом:

http://localhost/Default.aspx?StateValue=J1HKJH912IRWYQOICNOUQW

или

http://localhost/SomePage.aspx?Data=NIWQ7DWIU9WQ

При таком способе сохранения состояния, после перенаправления пользователя на новую (или ту же самую) страницу, в GET-параметрах передается ее состояние. При этом не имеют значения названия ключей или типы страниц.

Подобный подход удобен, когда необходимо передавать небольшие по объему, текстовые данные, которые не являются секретными. Если требуется работать с большим объемом данных или передаваемые данные не являются публичными, то нужно отказаться от этого способа сохранения состояния в пользу других методов. Нужно четко понимать, что если передавать с помощью строки запроса набор данных, то эти данные изменяют вид адреса страницы; если этих данных будет слишком много, то адрес страницы будет не читаем, что иногда неудобно.

По этим причинам подобный способ сохранения состояния хоть и используется в практике разработки веб-приложений, но его популярность очень мала. Вместо этого зачастую используются другие способы сохранения состояния.

Состояние вида (ViewState) позволяет передавать состояние между HTTP-запросами в рамках одной и той же страницы.

Платформа ASP.NET Web Forms (см. далее) содержит специальный способ обработки формы, который называется Postback. Идея этого механизма состоит в том, чтобы отправить данные на сервер с помощью HTTP-метода POST, при котором все поля формы также отправляются на сервер и при этом обращение осуществляется к той же самой странице. После обращения к веб-странице посредством механизма Postback форма как правило совершает определенный цикл обработки и модифицирует содержимое или внешний вид формы.

Использование механизма ViewState тесно связано с механизмом Postback. Механизм ViewState обеспечивает передачу данных между HTTP-запросами на основе скрытого поля, которое хранится в HTML-коде страницы. Если странице требуется сохранить состояние между запросами Postback, она сохраняет эти значения в скрытом поле HTML. При следующем Postback-запросе эти данные снова будут отправлены на сервер, где будут обработаны. Так процесс может повторяться несколько раз, пока происходят обращения Postback к данной форме. Однако, состояние ViewState теряется при переходе к другой странице.

Скрытое поле ViewState в коде HTML выглядит следующим образом.


Однако, если в состояние вида ViewState добавить какие-то данные, то оно видоизменится и может стать таким, как показано ниже.


Как видно, данные во ViewState хранятся в закодированном виде (не зашифрованном!) по алгоритму base64. При обработке Postback-запроса среда исполнения анализирует содержимое скрытого поля и помещает данные из него в объект ViewState (коллекция "ключ-значение"), который доступен разработчикам. В процессе обработки страницы содержимое объекта ViewState может изменяться, после чего в конце цикла обработки страницы этот объект трансформируется в строку (сериализуется), кодируется при помощи алгоритма base64 и помещается в скрытое поле. Таким образом, для работы с этим способом сохранения состояния необходимо использовать объект ViewState как показано ниже.


Как правило, при разработке приложений редко приходится напрямую пользоваться объектом ViewState. Обычно, объект ViewState используют элементы управления для сохранения своего состояния. Для управления использованием механизма ViewState у элементов управления есть свойство EnableViewState, которое по умолчанию включено. Если разработчику не требуется подобное поведение для элемента управления, он может отключить использование ViewState для него.

Приведенный способ сохранения состояния является достаточно удобным, но порождает ряд дополнительных проблем.

Во-первых, при частом использовании ViewState размер скрытого поля страницы быстро разрастается и может достигать огромных размеров. Это увеличивает размер страницы и, несомненно, сказывается на времени передачи страницы от сервера клиенту.

Во-вторых, у этого механизма существует потенциальная угроза перехвата и подмены данных в поле ViewState. Для решения проблемы с подменой данных можно включить механизм дополнительной защиты – хеш-код. При включении этого механизма в состоянии вида хранится надежно зашифрованная контрольная сумма. Это позволяет отследить подмену состояния вида и среагировать на эту ситуацию. Для включения этого механизма защиты необходимо установить свойство текущей страницы EnableViewStateMAC в значение True. Однако даже если использовать хеш-коды, данные состояния вида все равно остаются доступными для чтения и существует угроза перехвата этих данных. Чтобы исключить возможность перехвата данных можно включить шифрование состояния вида. Для этого необходимо установить свойство ViewStateEncryptionMode у текущей страницы в значение Always.

В целом, состояние вида ViewState используется для передачи данных между запросами Postback и в некоторых ситуациях может быть полезным.

Другим способом сохранения состояния является состояние сеанса (Session) или просто сессия. Этот способ сохранения состояния позволяет сохранять данные на протяжении всего сеанса работы пользователя с веб-приложением. В этом случае нет ограничения на сохранение состояния в рамках одной страницы – состояние сеанса доступно на протяжении работы с каждой страницей.

Каким образом работает этот механизм? Состояние сеанса базируется на встроенной в браузер возможности сохранять Cookie – небольшие данные, которые хранятся на стороне клиента. Если серверу необходимо сохранить какие-то данные в браузере пользователя, он генерирует специальный HTTP-заголовок, который включается в состав HTTP-ответа. При получении ответа браузер анализирует HTTP-ответ на наличие подобных заголовков и, в случае если такой заголовок обнаружен, сохраняет представленные данные на локальном компьютере в специальной папке. После этого при каждом обращении браузера к данному веб-приложению, браузер будет добавлять специальные HTTP-заголовки к своим HTTP-запросам. Таким образом, у сервера есть возможность сохранить на клиенте какие-то данные и получать к ним доступ при каждом обращении клиента к серверу.

Механизм Cookie сам по себе в какой-то степени является способом сохранения состояния. Однако, если его использовать как средство сохранения состояния для большого объема данных, то объем передаваемых данных от клиента к серверу и обратно существенно возрастает. Кроме того, существует потенциальная угроза получения данных из Cookie на стороне клиента, поскольку браузер никак не защищает эти данные. Именно поэтому был разработан механизм сохранения состояния сеанса.

Основная идея состояния сеанса заключается в следующем. При первом обращении браузера к серверу (когда Cookie чистые) сервер создает специальную область памяти, которой назначает уникальный идентификатор. Этот идентификатор сервер записывает в Cookie браузера. После этого браузер каждый раз будет сообщать этот идентификатор серверу. Теперь на сервере можно использовать выделенную для каждого пользователя область памяти для сохранения туда различных данных. При этом каждый пользователь будет иметь доступ к своему участку памяти. В данном случае этот идентификатор является идентификатором сессии. Поскольку пользователи не могут знать идентификаторов сессии других пользователей, сессия в каком-то смысле является более защищенной. Более того, в этом случае в сессии можно сохранять большие объемы информации без необходимости увеличения объема передаваемой информации между клиентом и сервером.

Однако, в таком случае при длительной работе сервера существует опасность, что память сервера закончится. Для того, чтобы этого избежать существует время жизни сессии. Это означает, что если пользователь с определенным идентификатором сессии не проявлял активность в течении определенного времени, то данные, ассоциированные с его идентификатором сессии удалятся с сервера. Это позволяет вовремя очищать сервер от лишних данных.

Как правило, в сессии может храниться идентификатор пользователя, его настройки, а также другая специфичная для каждого пользователя информация. Для работы с состоянием сеанса используется объект Session. По аналогии с ViewState, объект Session является коллекцией "ключ-значение", а работать с ним можно следующим образом.


Важным отличием состояния сеанса Session от состояния вида ViewState заключается в том, что в Session можно сохранять даже те объекты, которые не поддаются сериализации (преобразованию к текстовому представлению). Например, к таким объектам относится объект подключения к SQL Server и др.

Наконец, последним способом сохранения состояния является состояние приложения Application. От предыдущих способов сохранения состояния его отличает то, что Application содержит глобальную информацию, доступную всем пользователям одновременно в рамках всех страниц веб-приложения. Это означает, что при сохранении информации в объект Application одним пользователем, другой пользователь, обратившись к приложению, также может получить доступ к этой информации. Обычно за сохранение состояния приложения отвечает объект приложения HttpApplication, доступный по имени Application.

Работа с объектом Application осуществляется аналогичным образом, как и два предыдущих способа. Объект Application – это коллекция "ключ-значение". Для работы с этим объектом может использоваться следующий код.


Однако, к объекту Application (как и к любым другим глобальным данным) следует относиться осторожно, поскольку глобальные состояния могут вносить дополнительную сложность в программный код.

Таким образом, видно, что платформа ASP.NET обладает богатыми возможностями по сохранению состояния между HTTP-запросами. В данной лекции мы рассмотрели основные способы сохранения состояния и в каждой конкретной ситуации стоит выбирать именно тот способ, который наиболее удобен в этой ситуации.

Краткие итоги

Сложность разработки веб-приложений состоит в том, что взаимодействие по протоколу HTTP не предполагает сохранения состояния между обращениями. Однако, это бывает очень необходимо в большом числе ситуаций. Для этого в ASP.NET существует ряд инструментов для сохранения состояния. Состояние вида ViewState позволяет сохранять состояние между обращениями клиента к одной и той же странице. Состояние сеанса Session позволяет сохранять состояние для конкретного пользователя для всего веб-приложения. Наконец, состояние приложения Application позволяет сохранять глобальное состояние, доступное каждому пользователю в рамках приложения. Все эти способы доступны для работы через коллекции в стиле "ключ-значение" и очень просты в использовании.

Контрольные вопросы

  • Каким образом происходит компиляция ASP.NET приложения?
  • Как компилируются страницы ASPX?
  • Что такое частичный (partial) класс?
  • Каким образом среда исполнения ASP.NET может отслеживать изменение страниц ASP.NET?
  • Что происходит при изменении страниц ASP.NET на веб-сервере?
  • Для чего нужна предкомпиляция приложения?
  • Какие виды предкомпиляции приложения существуют в ASP.NET?
  • Что такое домен приложения?
  • Что представляет собой механизм отложенной инициализации?
  • Для чего нужны глобальные события приложения?
  • Назовите основные глобальные события приложения.
  • Каким образом можно задать обработчик для глобальных событий приложения?
  • Какие служебные объекты существуют в ASP.NET?
  • Для чего нужны служебные объекты ASP.NET?
  • Чем отличаются зарезервированные папки ASP.NET от обычных папок в составе веб-приложения?
  • Назовите основные типы зарезервированных папок ASP.NET.
  • Каким образом строится конфигурация ASP.NET приложений?
  • Каким образом реализован механизм наследования конфигурации ASP.NET приложений и для чего он необходим?
  • Чем отличаются файлы machine.config и web.config?
  • Какой базовый класс используется для создания класс-обработчика конфигурационной секции ASP.NET?
  • Что такое сохранение состояния?
  • Какие способы сохранения состояния доступны в ASP.NET?
  • Каким образом работает состояние вида (ViewState)?
  • Каким образом работает состояние сеанса (Session)?
  • Каким образом работает состояние приложения (Application)?
  • Приведите примеры правильного применения для каждого из способов сохранения состояния.
Марина Воробьева
Марина Воробьева
Виктория Ткаченко
Виктория Ткаченко

Проигрыватель не работает. После нажатия кнопки Play ничего не происходит.

Азиз Рахимов
Азиз Рахимов
Россия, М/О Ленинская район г.Видное ул.Центральная д.32
Борис Логунов
Борис Логунов
Россия, Moscow