Управление состоянием страниц на клиенте
Сохранение данных в состоянии сеанса
Любой пользователь при первом обращении к приложению получает свой сеанс, который выражается в выделении некоторого объема памяти на стороне сервера для хранения данных любого типа. Доступ к этим совместным данным осуществляется любой страницей через присоединенный к ней объект-словарь Session. За счет этого можно сохранять информацию на одной странице, а получать к ней доступ с другой страницы.
При поступлении первого клиентского запроса на объект страницы ASP.NET генерирует идентификатор сеанса размером 42 байта. Этот идентификатор сеанса включается в отклик сервера и является уникальным в пределах приложения. Если ни одна из страниц приложения, к которым обращается пользователь, не записывает в объект Session данные, то броузер не возвращает его в запросе серверу. Вместо этого сервер при каждом запросе генерирует новый идентификатор сеанса и включает его в отклик. Стоит только странице записать какие-нибудь данные в объект Session, идентификатор сеанса сразу фиксируется и запоминается броузером. После этого начинается обратный процесс, теперь уже броузер с каждым запросом начинает посылать на сервер сохраненный идентификатор сеанса, даже если в дальнейшем мы полностью очистим объект Session.
Когда клиент (броузер) присылает идентификатор сеанса, сервер по нему автоматически извлекает из места хранения данные сеанса и заполняет ими объект Session созданной страницы. После чего данные сеанса становятся доступными в коде этой страницы.
Идентификатор сеанса может пересылаться серверу с запросом двумя способами:
- С помощью cookie-набора с зарезервированным именем ASP.NET_SessionId
- С помощью включения в URL для клиентов, не поддерживающих cookie-наборы (использование измененных URL - адресов)
Идентификатор сеанса можно получить как значение Response. Cookies["ASP.NET_SessionID"] - при формировании первого отклика, или Session. SessionID - всегда. Но конкретное его значение нас, как правило, не интересует, поскольку процесс распознавания выполняется автоматически.
Данные сеанса могут сохраняться ASP.NET в одном из трех мест на сервере, определяемых свойством Mode объекта Session:
- В оперативной памяти сервера внутри процесса - текущего домена приложения (режим InProc - установлен по умолчанию)
- В оперативной памяти сервера вне процесса в специальной службе Windows под названием ASP.NET State Service (режим StateServer )
- Вне процесса на жестком диске в базе данных SQL Server (режим SQLServer )
Состояние сеанса утрачивается в следующих случаях:
- Пользователь закрывает и вновь запускает броузер
- Пользователь получает доступ к приложению через другой броузер
- Из-за простоя сеанса больше определенного времени по причине отсутствия запросов от клиента (по умолчанию 20 минут)
- Программист завершает сеанс методом Session. Abandon()
- Если сеанс создается внутри текущего домена, то при переходе приложения в новый домен сеанс будет потерян
Сеанс является экземпляром класса System.Web.SessionState. HttpSessionState и может частично управляться из кода. В таблице приведены некоторые свойства и методы класса HttpSessionState
Начальное состояние сеанса устанавливается в конфигурационном файле web.config в секции <sessionState>. Настройки секции <sessionState> поддерживаются классом System.Web.Configuration.SessionStateSection через его свойства, но имена свойств в кофигурационном файле начинаются с символа нижнего регистра. Вот некоторые наиболее важные из них
При включенном режиме cookieless="true" броузер автоматически встраивает идентификатор сеанса в URL всех относительных ссылок. Это же справедливо и при автоматической переадресации на новую страницу методом Response.Redirect(" Относительный_адрес") с полным циклом. Для того, чтобы указать системе, что идентификатор сеанса должен передаваться секретным протоколом, нужно установить Response.Cookies["ASP.NET_SessionID"].Secure = true;
Приведем пример использования сеанса.
Упражнение 10. Использование механизма сессий
- Отредактируйте файл web.config приложения как показано ниже
<?xml version="1.0" encoding="utf-8"?> <configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0"> <system.web> <compilation debug="true" /> <sessionState cookieless="true" regenerateExpiredSessionId="true" /> </system.web> </configuration>Листинг 35.22. Файл web.config с включенным режимом Cookieless
- Добавьте страницу с именем SessionCookieless.aspx с совмещенным кодом, которую заполните так
<%@ Page Language="C#" EnableViewState="false" %> <script runat="server"> int clicks = 1; const int maxCol=2; HtmlTable table; protected void Page_Load(object sender, EventArgs e) { string[] headers = { // Имена свойств секции sessionState "Cookieless", "Mode", "Timeout", "RegenerateExpiredSessionId", "CookieName", // Дополнительная информация "SessionID", "numRequest", "currentTime" }; // Создаем объекты пользовательского интерфейса // Текстовая метка заголовка Label label = new Label(); form1.Controls.Add(label); label.Text = "<h2>Использование сеансов Session</h2>"; if (!IsPostBack) { // Получаем всю информацию о параметрах конфигурации System.Configuration.Configuration config; config = System.Web.Configuration.WebConfigurationManager. OpenWebConfiguration(this.Request.ApplicationPath); // Объявляем ссылку на объект SessionStateSection System.Web.Configuration.SessionStateSection sessionState; // Поиск элемента <sessionState> в элементе <system.web> sessionState = (System.Web.Configuration.SessionStateSection) config.GetSection(@"system.web/sessionState"); //sessionState.Timeout = TimeSpan.FromMinutes(1); // Формируем таблицу и сохраняем ее в сеансе table = new HtmlTable(); table.Border = 1; for (int i = 0; i < headers.Length; i++) { // Создаем строку HtmlTableRow row = new HtmlTableRow(); table.Rows.Add(row); // Создаем ячейки в строке for (int j = 0; j < maxCol; j++) { HtmlTableCell col = new HtmlTableCell(); row.Cells.Add(col); if (j == 0)// Левый столбец { col.InnerHtml = headers[i] + ": "; col.Align = "right"; col.BgColor = "Yellow";// Цвет фона } else // Правый столбец { // Применяем методику отражения типов System.Type type = typeof(System.Web.Configuration. SessionStateSection); // Извлекаем публичное свойство по его имени System.Reflection.PropertyInfo property = type.GetProperty(headers[i]); if (property != null) { col.InnerHtml = " "; // Извлекаем значение свойства из экземпляра класса col.InnerHtml += property.GetGetMethod(). Invoke(sessionState, null).ToString(); } else { // Маркируем ячейку, чтобы потом найти col.ID = headers[i]; } col.BgColor = "#CCFFFF";// Цвет фона } } } // Сохраняем информацию в сеансе при первом запросе this.Session.Add("table", table); this.Session["clicks"] = clicks; } else { // Извлекаем информацию из сеанса при каждой обратной отсылке table = (HtmlTable)this.Session["table"]; clicks = (int)this.Session["clicks"]; // Сохраняем новое значение this.Session["clicks"] = ++clicks; } // Добавляем таблицу на форму form1.Controls.Add(table); // Корректируем таблицу ((HtmlTableCell)Page.FindControl("SessionID")).InnerHtml = " " + this.Session.SessionID; ((HtmlTableCell)Page.FindControl("numRequest")).InnerHtml = " " + clicks.ToString(); ((HtmlTableCell)Page.FindControl("currentTime")).InnerHtml = " " + DateTime.Now.ToLocalTime(); // Новая строка HTML HtmlGenericControl br = new HtmlGenericControl(); br.InnerHtml = "<br />"; form1.Controls.Add(br); // Кнопка Submit Button submit = new Button(); form1.Controls.Add(submit); submit.Text = "Отправить"; } </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Untitled Page</title> </head> <body> <form id="form1" runat="server" style="text-align: center;"> </form> </body> </html>Листинг 35.23. Код страницы SessionCookieless.aspx
- Назначьте страницу SessionCookieless.aspx стартовой и выполните ее
Клиентский результат будет таким
Обратите внимание, что идентификатор сеанса встроен в URL при значении параметра Cookieless = "UseUri". Отметьте также, что интерфейсная часть страницы пустая - все создается динамически. Часть выводимой в таблицу информации мы добыли из объекта класса SessionStateSection, который создается по настройкам конфигурационного файла. Для более лаконичного кода мы применили методику отражения типов, позволившую опосредованно вызывать свойства объекта. В сессиях можно сохранять объекты любого типа, а не только строки. Но при извлечении их нужно явно приводить к соответствующему типу.