Опубликован: 07.05.2010 | Доступ: свободный | Студентов: 1678 / 62 | Оценка: 4.56 / 4.06 | Длительность: 34:11:00
Лекция 10:

Управление состоянием 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>
  • Запустите приложение и убедитесь в его работоспособности

Результат после восстановления ранее сохраненной в состоянии вида информации будет примерно таким

  • Удалите из секции <system.web> файла Web.config параметр отключения проверки достоверности <pages validateRequest="false" /> и включите его как атрибут ValidateRequest="false" в состав директивы @ Page страницы ViewStateObjects.aspx, чтобы он действовал только на одну эту страницу