Эндрю Троелсен - ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание
Исходный код. Файлы примера SimpleStateExample размещены в подкаталоге, соответствующем главе 24.
Технологии управления состоянием ASP.NET
ASP.NET предлагает целый ряд механизмов, которые можно использовать для поддержки информации состояния в Web-приложениях. В частности, у вас на выбор есть следующие варианты.
• Использование данных состояния представлений ASP.NET.
• Использование данных состояния элементов управления ASP.NET.
• Определение переменных уровня приложения.
• Использование объектов кэширования.
• Определение переменных сеансового уровня.
• Взаимодействие с данными cookie.
Мы рассмотрим детали каждого из указанных подходов по очереди, начиная с темы состояния представлений ASP.NET.
Роль состояния представлений ASP.NET
Термин состояние представлений уже упоминался множество раз здесь и в предыдущей главе без формального определения, так что позвольте демистифицировать этот термин раз и навсегда. В рамках классической технологии ASP требовалось, чтобы Web-разработчики вручную указывали значения элементов формы в процессе построения исходящего HTTP-ответа, Например, если поступивший HTTP-запрос содержал пять текстовых блоков с конкретными значениями, файл *.asp должен был извлечь текущие значения (с помощью коллекций Form или QueryString объекта Request) и вручную поместить их в поток HTTP-ответа (ясно, что это было весьма неудобное решение). Если разработчик этого не делал, то пользователь видел пять пустых текстовых блоков.
В ASP.NET больше не требуется вручную извлекать и указывать значения, содержащиеся в HTML-элементах, поскольку среда выполнения ASP.NET автоматически создает в форме скрытое поле (__VIEWSTATE), которое включается в поток обмена между браузером и соответствующей страницей. Данные, присваиваемые этому полю, представляют собой строку в кодировке Base64, состоящую из пар имен и значений, которые характеризуют каждый элемент графического интерфейса на данной странице.
Обработчик события Init базового класса System.Web.UI.Page отвечает за чтение значений, обнаруженных в поле __VIEWSTATE, и заполнение соответствующих членов-переменных в производном классе (именно поэтому по крайней мере рискованно использовать доступ к параметрам состояния Web-элемента в контексте обработчика события Init страницы).
Точно так же перед исходящим ответом браузеру данные __VIEWSTATE используется для заполнения элементов формы, чтобы текущие значения HTML-элементов оставались такими же, какими они были до повторного обращения к серверу.
Очевидно, лучшим аспектом поведения ASP.NET в этом отношении является то, что все это происходит без вашего вмешательства. При этом, при желании, вы можете изменить или отключить такое принятое по умолчанию поведение. Чтобы понять, как это сделать, давайте рассмотрим конкретный пример использования данных состояния представлений.
Демонстрация использования состояния представлений
Создайте новое Web-приложение ASP.NET с названием ViewStateApp. В исходную страницу *.aspx добавьте один Web-элемент управления ASP.NET ListBox и один тип Button. Обработайте событие Click для Button, чтобы обеспечить пользователю возможность вторичного обращения к Web-серверу.
protected void btnDoPostBack_Click(object sender, EventArgs e) {
// Для вторичного обращения к серверу.
}
Теперь, используя окно свойств Visual Studio 2005, получите доступ к свойству Items и добавьте в ListBox четыре элемента ListItem. Результат должен быть примерно таким.
‹asp:ListBox ID="myListBox" runat="server"›
‹asp:ListItem›Элемент 1‹/asp:ListItem›
‹asp:ListItem›Элемент 2‹/asp:ListItem›
‹asp:ListItem›Элемент 3‹/asp:ListItem›
‹asp:ListItem›Элемент 4‹/asp:ListItem›
‹/asp:ListBox›
Заметьте, что здесь элементы ListBox в файле *.aspx указаны явно. Вы уже знаете, что все элементы ‹asp:›, обнаруженные в пределах HTML-формы, автоматически обновляют свое HTML-представление перед отправкой HTTP-ответа (конечно, если они при этом имеют атрибут runat="server").
Директива ‹%@Page%› имеет необязательный атрибут enableViewState, который по умолчанию установлен равным true. Чтобы отменять такое поведение, просто измените содержимое директивы ‹*@Page%› так, как предлагается ниже.
‹%@Page EnableViewState ="false" Language="C#" AutoEventWireup="true" CodeFilе="Dеfault.aspx.cs" Inherits="_Default" %›
Но что же в действительности означает отключение учета состояния представлений? Ответ на этот вопрос зависит от многих факторов. В соответствии с предложенным выше определением данного термина вы могли бы предположить, что при отключении учета состояния представлений для файла *.aspx значения ListBox не будут сохраняться при вторичных запросах к Web-серверу. Однако, выполнив приложение в том виде, в каком это приложение находится сейчас, вы можете с удивлением обнаружить, что информация в ListBox сохраняется независимо от того. сколько раз вы повторно обращаетесь к странице. Фактически, если рассмотреть исходный HTML-код, возвращаемый браузеру, вы увидите, что скрытое поле __VIEWSTATE там все равно присутствует.
‹input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value= "/wEPDwUKMTYlMjcхNTсxNmRkОXbNzW5+R2VDhNWtEtHMM+yhxvU=" /›
Причиной, по которой строка состояния представлений не исчезает, является то, что файл *.aspx явно определяет элементы ListBox в контексте HTML-дескриптора ‹form›. Поэтому элементы ListBox будут автоматически генерироваться при каждом ответе Web-сервера клиенту.
Но предположим, что значения вашего типа ListBox динамически указываются в файле внешнего кода поддержки, а не в рамках HTML-определения ‹form›. Сначала удалите декларации ‹asp:ListItem› из имеющегося файла *.aspx.
‹asp:ListBox ID="myListBox" runat="server"›
‹/asp:ListBox›
Затем задайте элементы списка в обработчике события Load в рамках файла с внешним кодом поддержки.
protected void Page_Load(object sender, EventArgs e) {
if (!IsPostBack) {
// Динамическое заполнение ListBox.
myListBox.Items.Add("Элемент 1");
myListBox.Items.Add("Элемент 2");
myListBox.Items.Add("Элемент 3");
myListBox.Items.Add("Элемент 4");
}
}
Для обновленной страницы вы обнаружите, что при первом запросе страницы браузером значения в ListBox присутствуют и учитываются. Однако после вторичного запроса ListBox становится пустым. Первым правилом состояния представлений ASP.NET является то, что они учитывается только при наличии элементов, чьи значения динамически генерируются программным кодом. Если вы явно укажете значения в рамках дескриптора ‹form› в файле *.aspx, состояние этих элементов всегда будет восстанавливаться при вторичных запросах (даже если вы установите для enableViewState значение false для данной страницы).
Данные состояния представлений оказываются наиболее полезными при работе с динамическими Web-элементами управления, которые должны обновляться при каждом вторичном обращении к серверу (примером такого Web-элемента является элемент управления GridView ASP.NET, заполняемый при обращении к базе данных). Если вы не отключите учет состояния представлений для страниц, содержащих такие элементы, состояние таблиц будет представлено в скрытом поле__ VIEWSTATE. Сложные страницы могут содержать очень много Web-элементов управления ASP.NET, поэтому вы можете себе представить, насколько большой может быть соответствующая строка. При этом содержимое HTTP-цикла "запрос-ответ" может оказаться достаточно объемным, что может стать определенной проблемой для коммутируемых Web-соединений. В таких случаях может быть оправданным отключение учета состояния представлений для всей страницы.
Если идея отключения учета представлений для всего файла *.aspx кажется вам слишком радикальной, вспомните о том, что каждый потомок базового класса System.Web.UI.Control наследует свойство EnableViewState, с помощью которого очень просто отключить учет состояния представлений для каждого конкретного элемента управления в отдельности.
‹asp:GridView id="myHugeDynamicallyFilledDataGrid" runat="server" EnableViewState="false"›
‹/asp:GridView›
Замечание. Страницы ASP.NET резервируют небольшую часть строки __VIEWSTATE для внутреннего использования. Именно поэтому поле __VIEWSTATE появляется в браузере клиента даже тогда, когда учет состояния представлений отключен для всей страницы (или для всех элементов управления).
Добавление пользовательских данных состояния представлений
В дополнение к свойству EinableViewState базовый класс System.Web. UI.Control предлагает наследуемое свойство ViewState. Это свойство в фоновом режиме обеспечивает доступ к типу System.Web.UI.StateBag, представляющему все данные поля __VIEWSTATE. С помощью индексатора типа StateBag вы можете встроить пользовательскую информацию в скрытое поле __VIEWSTATE формы, используя для этого подходящий набор пар имён и значений. Вот простой пример.