Разработка на ASP.NET. Жизненный цикл страницы, пользовательский интерфейс
6.2.6. Использование Session
Состояние сеанса (Session) – это самая сложная технология управления состояниями. Она позволяет сохранять информацию на одной странице и затем получать к ней доступ с другой страницы, а также поддерживает объекты любого типа, включая специальные, создаваемые самим разработчиком, типы данных. Лучше всего то, что состояние сеанса использует тот же основанный на коллекциях синтаксис, что и состояние просмотра. Единственное отличие – имя встроенного свойства страницы, которое в данном случае выглядит так: Session.
Каждый клиент, который получает доступ к приложению, имеет свой сеанс и свою отдельную коллекцию данных. Состояние сеанса идеально подходит для сохранения таких данных, как элементы, которые находятся в "корзине для покупок" пользователя, когда он переходит с одной страницы на другую. Но использование состояния сеанса имеет некоторые недостатки. Хотя оно решает многие из проблем, которые возникают в случае применения других технологий управления состояниями, его использование вынуждает Веб-сервер сохранять дополнительную информацию в памяти. Эта необходимость в использовании дополнительных ресурсов памяти сервера, пусть даже в маленьком объеме, очень быстро может достичь угрожающего производительности уровня, когда к сайту начнут получать доступ сотни или тысячи клиентов.
6.2.6.1. Архитектура сеанса
Управление сеансом не является частью HTTP-стандарта. Поэтому ASP.NET приходится выполнять некоторую дополнительную работу, чтобы отследить информацию сеанса и привязать ее к соответствующему ответу.
ASP.NET отслеживает каждый сеанс с помощью уникального 120-ти битового идентификатора. ASP.NET использует для генерации этого значения оригинальный алгоритм, что, согласно статистике, обеспечивает гарантию того, что число будет уникальным и достаточно случайным для того, чтобы злонамеренный пользователь не смог воссоздать или угадать идентификатор сеанса, которым будет пользоваться данный клиент. Этот идентификатор является единственным фрагментом информации, который передается между Веб-сервером и клиентом. Когда клиент предоставляет идентификатор сеанса, ASP.NET отыскивает соответствующий сеанс, извлекает из сервера состояний "сериализованные" данные, преобразовывает их в "реальные" объекты и помещает эти объекты в специальную коллекцию для того, чтобы к ним можно было получить доступ в коде. Весь этот процесс выполняется автоматически.
Рассмотрим, как ASP.NET хранит данные в сессии.
Когда ASP.NET обрабатывает HTTP-запрос, тот проходит через конвейер различных модулей, которые могут реагировать на события приложения. Одним из модулей в этой цепочке является модуль SessionStateModule (который находится в пространстве имен System.Web.SessionState ). Этот модуль генерирует идентификатор сеанса, извлекает из внешних поставщиков состояния данные сеанса и затем привязывает эти данные к контексту вызовов запроса. Он также сохраняет данные состояния сеанса, когда обработка страницы завершается. Однако важно понимать, что модуль SessionStateModule фактически не хранит данные сеанса. Вместо этого, состояние сеанса сохраняется во внешних компонентах, которые называются поставщиками состояния. Весь этот процесс показан на рис. 6.4.
Состояние сеанса представляет собой пример сменной архитектуры в ASP.NET. Поставщиком состояния может быть любой класс, который реализует интерфейс IStateClientManager, а это означает, что способ работы состояния сеанса можно настроить, просто создав (или купив) новый .NET-компонент. ASP.NET включает три заготовленных поставщика состояния, которые позволяют сохранять информацию в процессе, в отдельной службе и в базе данных SQL Server.
6.2.6.2. Использование состояния сеанса
Взаимодействовать с состоянием сеанса можно используя класс System.Web.SessionState.HttpSessionState, который на Веб-странице ASP.NET доступен в виде встроенного объекта Session. Синтаксис для добавления элементов в эту коллекцию и их извлечения выглядит практически точно так же, как и синтаксис, который используется для добавления элементов в состояние просмотра страницы.
Например, сохранить объект DataSet в памяти сеанса можно следующим образом:
Session["ds"] = ds;
После этого, его можно извлечь с помощью соответствующей операции преобразования:
ds = (DataSet)Session["ds"];
Контекст состояния сеанса охватывает все приложение и является глобальным для текущего пользователя. Состояние сеанса утрачивается в следующих случаях:
- если пользователь закрывает и заново запускает браузер;
- если пользователь получает доступ к той же странице через другое окно браузера при сохранении доступа к Веб-странице из исходного окна браузера (разные браузеры ведут себя по-разному в такой ситуации);
- если сеанс завершается из-за отсутствия активности со стороны пользователя (по умолчанию сеанс автоматически завершается после 20 минут простоя);
- если программист завершает сеанс, вызывая метод Session.Abandon().
В первых двух случаях, сеанс фактически остается в памяти, потому что Веб-сервер не имеет ни малейшего понятия о том, что клиент закрыл или сменил окно браузера. Сеанс будет находиться в памяти, оставаясь недоступным, до тех пор, пока, в конце концов, не истечет срок его действия.
6.2.6.3. Поставщики состояния сеанса
Параметр настройки состояния сеанса Mode позволяет указывать, какой поставщик состояния сеанса должен использоваться для хранения данных состояния сеанса между запросами. Допустимые значения описываются ниже.
6.2.6.3.1. Off
Установка значения Off приводит к отключению функции управления состоянием сеанса для всех страниц в приложении. Это может немного повысить производительность Веб-сайтов, которые не используют состояние сеанса.
6.2.6.3.2. InProc
Установка значения InProc напоминает подход, который использовался для хранения состояния сеанса в классической версии ASP. Это значение указывает ASP.NET хранить информацию в текущем домене приложения, что обеспечивает наилучшую производительность, но наименьший срок службы: если администратор перезапустит сервер, данные состояния будут утрачены.
Значение InProc используется по умолчанию и подходит для большинства Веб-сайтов небольшого размера. Однако в сценарии с группой серверов от него не будет никакого толку. Сделать так, чтобы состояние сеанса могли совместно использовать сразу несколько серверов, можно только воспользовавшись внепроцессным поставщиком или службой состояний SQL Server. Еще одна причина, по которой установка значения InProc может быть нежелательной, состоит в том, что оно подразумевает создание более "хрупких" сеансов. В ASP.NET, домены приложений нередко создаются заново в ответ на различные операции типа изменения конфигурационных настроек или обновления страниц, а так же при достижении определенных пороговых значений (независимо от того, произошла ошибка или нет). Если будет обнаружено, что домен приложения часто перезапускается, что приводит к преждевременному завершению сеансов, можно попытаться устранить этот эффект, изменив те или иные параметры модели процесса, или воспользоваться другим более надежным поставщиком состояния сеанса.
Прежде чем использовать внепроцессную модель (StateServer) или службу состояний SQL Server, придется принять во внимание следующие моменты:
- Когда выбирается режим StateServer или SqlServer, сохраняемые в состоянии сеанса объекты должны допускать сериализацию. Иначе ASP.NET не сможет передавать их службе состояний или сохранять в базе данных.
- Если ASP.NET обслуживает группа Веб-серверов, придется выполнить некоторые дополнительные конфигурационные шаги для гарантии того, что все Веб-серверы будут работать синхронно. Иначе, не исключено, что один сервер будет кодировать информацию не так, как другой, а это, несомненно, приведет к появлению проблем, если во время сеанса пользователь будет перенаправляться от одного сервера к другому (решением этой проблемы является изменение раздела <machineKey> файла machine.config так, чтобы он был одинаковым на всех серверах).
- Если не используется внутрипроцессный поставщик состояния, событие SessionStateModule.End не будет инициироваться, и все обработчики этого события в файле global.asax или HTTP-модуле будут игнорироваться.
6.2.6.3.3. StateServer
В случае установки этого значения, ASP.NET будет использовать для управления состоянием отдельную службу Windows. Даже при запуске на том же самом Веб-сервере эта служба будет загружаться за пределами основного процесса ASP.NET, что обеспечивает для нее базовый уровень защиты, когда возникает необходимость перезапустить процесс ASP.NET. Недостатком такого подхода является то, что из-за того, что данные состояния передаются между двумя процессами, увеличивается время задержки. Если доступ к данным сеанса получается часто, и они часто изменяются, это может сильно замедлить работу.
Выбрав режим StateServer, обязательно следует указать значение для параметра stateConnectionString. Эта строка сообщает TCP/IP-адрес компьютера, на котором запускается служба StateServer, и номер его порта (который определяется ASP.NET и который, как правило, не требуется изменять). Это позволяет обслуживать службу StateServer на другом компьютере. Если не изменить значение этого параметра, будет использоваться локальный сервер (адрес которого выглядит так: 127.0.0.1).
6.2.6.3.4. SqlServer
Это значение указывает ASP.NET использовать для хранения данных сеанса базу данных SQL Server, применяя параметры, определенные в атрибуте sqlConnectionString. Такой способ управления состоянием является самым удобным, но и пока что самым медленным. Чтобы его можно было использовать, на сервере должна быть установлена база данных SQL Server.
Установка значения для атрибута sqlConnectionString выполняется по схеме, подобной той, что используется для получения доступа к данным ADO.NET. В целом это подразумевает указание источника данных (т.е. адреса сервера), имени пользователя и пароля, если только не используется интегрированная система безопасности SQL.
Обычно база данных состояния всегда называется "ASPState". Поэтому строка подключения в файле web.config не отображает явно имя базы данных. Вместо этого, она просто отражает месторасположение сервера и тип аутентификации, который будет использоваться:
<sessionState sqlConnectionString="data source=127.0.0.1;Integrated Security=SSPI" ... />
При желании использовать другую базу данных (с такой же структурой), необходимо установить для атрибута allowCustomSqlDatabase значение true и убедиться в том, что строка подключения включает параметр Initial Catalog, указывающий имя базы данных, которую следует использовать:
<sessionState allowCustomSqlDatabase="false" sqlConnectionString= "data source=127.0.0.1;Integrated Security=SSPI;Initial Catalog=CustDatabase" ... />
Выбрав режим SqlServer, также можное установить значение для необязательного атрибута sqlCommandTimeout. Этот атрибут указывает максимальное количество секунд, в течение которых должен ожидаться ответ от базы данных, прежде чем запрос будет отменен. По умолчанию ему присваивается значение, равное 30 секундам.
6.2.7. Ключевые термины
ASP.NET, Жизненный цикл страницы, Управление состоянием, ViewState, Строка запроса, Cookies, Состояние сеанса.