Управление состоянием 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>
- Запустите приложение и убедитесь в его работоспособности
Результат после восстановления ранее сохраненной в состоянии вида информации будет примерно таким