Управление состоянием ASP.NET
Упражнение 2
Этот пример подобен предыдущему, но в нем значения текстовых полей прежде поэлементно сохраняются в промежуточном объекте Hashtable, а затем этот объект целиком сохраняется в свойстве объекта страницы ViewState. Интерфейсная часть страницы остается в точности такой-же, как в предыдущем примере, а кодовая часть изменится. При этом, чтобы не менять интерфейсную часть, мы динамически (в кодовой части) добавим в конце коллекции формы form1 текстовую метку для отображения на клиенте содержимого промежуточного объекта-словаря.
-
Через панель Solution Explorer создайте копию страницы ViewStateTest.aspx и присвойте ей имя ViewStateObjects.aspx
-
Измените имя класса ViewStateTest на ViewStateObjects в кодовой и интерфейсной частях скопированной страницы -
Заполните кодовую часть следующим образом
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
public partial class ViewStateObjects : System.Web.UI.Page
{
private bool executeFlag = true;
// Создаем экземпляр промежуточного словаря
Hashtable dictionary = new Hashtable();
protected void cmdSave_Click(object sender, EventArgs e)
{
// Сохраняем присланные значения текстовых полей в словаре
SaveAllText(Table1.Controls, executeFlag);
// Сохраняем помеченный словарь целиком в состоянии вида
this.ViewState["contentsState"] = dictionary;
}
private void SaveAllText(ControlCollection controls, bool saveNested)
{
if (!saveNested)
return;
// Перебираем все дочерние элементы в переданной коллекции таблицы
foreach (Control control in controls)
{
// Выбираем элементы только текстовых полей и сохраняем
// их содержимое в промежуточном объекте, используя
// в качестве ключа идентификатор элемента
if (control is TextBox)
{
// Значения полей перед сохранением на всякий случай
// URL-кодируем как поступившие от ненадежного источника
// (предохраняемся от возможного ввода зловредных скриптов).
// Чтобы система не реагировала на угловые скобки в полях ввода,
// нужно в директиву @ Page интерфейсной части вставить атрибут
// ValidateRequest="false" или в секцию
// <pages validateRequest="false"> файла web.config
// Внимание!!! XML-файл web.config чувствителен к регистру символов
string text = ((TextBox)control).Text;
text = Page.Server.HtmlEncode(text);
// То же самое...
// text = HttpUtility.HtmlEncode(text);
// Добавляем в словарь обезвреженный текст
dictionary.Add(control.ID, text);
}
// На верхних уровнях объекта Table1 дочерними элементами
// являются строки и ячейки таблицы, поэтому продолжаем
// рекурсивно спускаться ниже, пока не встретим объекты TextBox.
// Флаг saveNested разрешает проверять вложенные уровни коллекций
if (control.Controls != null)
{
SaveAllText(control.Controls, saveNested);
}
}
}
protected void cmdRestore_Click(object sender, EventArgs e)
{
// Извлекаем из состояния вида пришедший с
// обратной отсылкой промежуточный объект и заполняем
// из него текстовые поля сохраненными значениями
RestoreAllText(executeFlag);
}
// Если доступ к функции явно не объявлен, то по умолчанию считается private
void RestoreAllText(bool restoreNested)
{
if (!restoreNested)
return;
// Извлекаем помеченные ранее данные из состояния
// вида в промежуточный объект-словарь
dictionary = (Hashtable)this.ViewState["contentsState"];
// Перебираем все элементы заполненного словаря и ищем на
// странице соответствующее текстовое поле. Заодно заполняем
// парами словаря текстовую метку для отсылки клиенту. Текстовую
// метку создадим динамически и добавим в конец коллекции формы
Label label = new Label();
form1.Controls.Add(label);
label.Text = "<hr />" + "<h2>Значения словаря</h2>";
foreach (DictionaryEntry pair in dictionary)
{
// Выделяем ключ и значение для очередной извлеченной пары
string key = pair.Key.ToString();
string value = pair.Value.ToString();
// Ищем на странице текстовое поле с соответствующим
// идентификатором, уникальным в пределах страницы
TextBox item = (TextBox)Page.FindControl(key);
if (item != null)
{
// Если нашли, заполняем поле и текстовую метку
item.Text = value;
label.Text += string.Format("Key={0}, Value={1}", key, value);
label.Text += "<br />";
}
}
}
}Поскольку мы взяли на себя проверку достоверности данных, введенных пользователем, то нужно отключить такую проверку системой ASP.NET при считывании запроса, поместив соответствующую инструкцию в директиву @ Page страницы или в файл конфигурации в секцию <pages>. При этом нужно строго учитывать регистр символов и в директиву @ Page атрибут помещать таким ValidateRequest="false", а в конфигурационный файл таким validateRequest="false". Это общее правило ASP.NET для случая, когда настройки допускают двойственное размещение.
-
Дополните файл конфигурации web.config секцией <pages> с отключенной проверкой достоверности<?xml version="1.0" encoding="utf-8"?> <configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0"> <system.web> <compilation debug="true" /> <pages validateRequest="false" /> </system.web> </configuration> -
Запустите приложение и убедитесь в его работоспособности
Результат после восстановления ранее сохраненной в состоянии вида информации будет примерно таким
