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

Управление состоянием ASP.NET

Восстановление состояния вида элемента списка через коллекцию запроса

Иногда состояние вида в элементе полезно отключить, чтобы уменьшить нагрузку на каналы связи. Но для некоторых элементов это нарушает их нормальную работу. Возьмем, например, списки ListBox и DropDownList. Когда они заполнены большим количеством элементов, объем пересылаемой информации состояния вида очень большой и это свойство лучше отключить. Для восстановления состояния выделенного элемента списка в этом случае можно воспользоваться информацией из коллекции Request.Form страницы. Проверим это на примере.

Упражнение 3

  • Добавьте к проекту страницу с именем ViewStateList.aspx без файла отделенного кода и назначьте ее стартовой
  • Оформите страницу так, чтобы код ее интерфейсной части был следующим
    <%@ Page Language="C#" %>
    	
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title>Untitled Page</title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div style="text-align: center">
        <h2>Отключение состояния вида в списках</h2>
            <asp:ListBox ID="ListBox1" runat="server" Height="200px" Width="150px" />
            &nbsp; &nbsp; &nbsp; &nbsp;
            <asp:DropDownList ID="DropDownList1"
                runat="server" Width="150px">
            </asp:DropDownList><br />
            <br />
            <asp:Button ID="Button1" runat="server" Text="Отправить" /></div>
        </form>
    </body>
    </html>
  • Этому коду в режиме проектирования соответствует следующее представление

  • Двойным щелчком на свободном месте страницы в режиме Design создайте блок скриптов с заготовкой обработчика Page_Load()
  • Поместите в обработчик Page_Load() код заполнения списков видимым содержимым, который будет срабатывать при каждом запросе страницы
    <script runat="server">
        
        // Поле класса страницы
        private const int maxCount = 1000;
        
        protected void Page_Load(object sender, EventArgs e)
        {
            // Заполняем списки программной генерацией значений
            for (int i = 0; i < maxCount; i++)
            {
                ListBox1.Items.Add("Опция " + (i + 1).ToString());
                DropDownList1.Items.Add("Опция " + (i + 1).ToString());
            }
        }
    </script>
  • Выполните страницу и убедитесь, что при каждом новом запросе по щелчку на кнопке Submit отмеченные пользователем опции списков возвращаются сервером сохраненными

Пока что это работает механизм автоматического сохранения состояния вида ASP.NET. Но давайте посмотрим, какой при этом получается объем пересылаемой информации, именно касающийся работы этого механизма. Для этого включим работу ASP.NET в режиме выдачи трассировки на индивидуальных страницах. Это можно сделать, если добавить атрибут Trace="true" в директиву @ Page страницы, либо через утилиту WAT, запустив ее командой Website/ASP.NET Configuration (или щелкнуть на пиктограмме в панели Solution Explorer ).

  • Запустите утилиту WAT, пойдите последовательно по ссылкам Application Configuration/Configure debugging and tracing и включите флажки "Capture tracing information" и "Display tracing information on ondividual pages". Закройте утилиту

В результате этих действий файл конфигурации примет вид

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
    <system.web>
        <trace enabled="true" pageOutput="true" />
        <compilation debug="true" />
    </system.web>
</configuration>
  • Вновь запустите страницу ViewStateList.aspx, поманипулируйте с интерфейсными элементами, выполните обратную отсылку и проанализируйте секцию Control Tree в результатах трассировки, которая будет, примерно, такой
Control Tree
Control UniqueID Type Render Size Bytes (including children) ViewState Size Bytes (excluding children) ControlState Size Bytes (excluding children)
__Page ASP.viewstatelist_aspx 910866 0 0
ctl02 System.Web.UI.LiteralControl 50 0 0
ctl00 System.Web.UI.HtmlControls.HtmlHead 46 0 0
ctl01 System.Web.UI.HtmlControls.HtmlTitle 33 0 0
ctl03 System.Web.UI.LiteralControl 14 0 0
form1 System.Web.UI.HtmlControls.HtmlForm 910736 0 0
ctl04 System.Web.UI.LiteralControl 129 0 0
ListBox1 System.Web.UI.WebControls.ListBox 227258 196036 0
ctl05 System.Web.UI.LiteralControl 47 0 0
DropDownList1 System.Web.UI.WebControls.DropDownList 227246 196036 0
ctl06 System.Web.UI.LiteralControl 32 0 0
Button1 System.Web.UI.WebControls.Button 78 0 0
ctl07 System.Web.UI.LiteralControl 12 0 0
ctl08 System.Web.UI.LiteralControl 20 0 0

Объем пересылаемой по каналам связи в оба конца информации получается огромным до неприличия. Причем с каждой новой отсылкой он катастрофически нарастает, добавляя к прежним сохраненным значениям сгенерированные в коде новые значения списков. Отключим сохранение состояния вида в списках, а для восстановления позиций выделенных пользователем опций воспользуемся тем фактом, что с каждым запросом эти значения передаются на сервер в словарь Request.Form объекта страницы.

  • Перейдите в режим Design редактора страницы ViewStateList.aspx, выделите одновременно оба списка и через панель Properties сбросьте свойства EnableViewState
  • Запустите страницу ViewStateList.aspx и убедитесь, что объем сохраняемого состояния вида для списков стал нулевым

Замечание. Если количество запросов превысит заданное параметром трассировки requestLimit значение (по умолчанию 10), то ASP.NET при исполнении не будет включать результаты трассировки в страницу. В этом случае нужно при очередном запуске тестового браузера вызвать через строку адреса страницу trace.axd и щелкнуть на ссылке "clear current trace" этой страницы. Включить безлимитную трассировку можно более просто - добавить в директиву @ Page страницы параметр Trace=true

Мы видим, что при отключении сохранения состояния вида резко уменьшился и общий объем страницы. Но сервер в своих откликах не сохраняет выбранные клиентом опции списков. Исправим этот недостаток программно.

  • Добавьте к странице код восстановления выбора пользователя в списках
<script runat="server">
    
    // Поле класса страницы
    private const int maxCount = 1000;
    
    protected void Page_Load(object sender, EventArgs e)
    {
        // Заполняем списки программной генерацией значений
        for (int i = 0; i < maxCount; i++)
        {
            ListBox1.Items.Add("Опция " + (i + 1).ToString());
            DropDownList1.Items.Add("Опция " + (i + 1).ToString());
        }
        
        // Отслеживание выделенных пользователем опций списков 
        if (this.IsPostBack)
        {
            string text = this.Request.Form["ListBox1"];
            ListBox1.Items.FindByText(text).Selected = true;
            text = this.Request.Form["DropDownList1"];
            DropDownList1.Items.FindByText(text).Selected = true;
        }
        else
            ListBox1.SelectedIndex = DropDownList1.SelectedIndex = 0;
    }
</script>

Броузер с обратной отсылкой присылает на сервер значения выделенных элементов списка, собираемых дескриптором <form> из HTML-кода, представленного примерно таким фрагментом

<select size="4" name="ListBox1" id="ListBox1" style="height:200px;width:150px;">
<option selected="selected" value="Опция 1">Опция 1</option>
<option value="Опция 2">Опция 2</option>
<option value="Опция 3">Опция 3</option>
..................................................
</select>

Фактически броузер посылает пару ListBox1=Опция 1, которая попадает в словарь Request.Form, доступный для извлечения и использования в коде страницы на стороне сервера. Мы находим это значение в сгенерированной коллекции значений списка и настраиваем этот элемент коллекции как выделенный. После таких настроек список сгенерирует в текущем отклике сервера нужный HTML-код, соответствующий состоянию списка на клиенте перед обратной отсылкой.

  • Запустите страницу ViewStateList.aspx с включенной трассировкой и убедитесь, что выбранные опции списков сохраняют свои позиции и ASP.NET генерирует небольшой объем клиентского кода

Таким образом мы выяснили, что состояние вида элементов управления, которое включено по умолчанию, не всегда является полезным либо просто не используется, и тогда его лучше отключать. Отключить состояние вида можно следующим образом:

  1. На уровне приложения для всех страниц в файле web.config корня web-дерева сайта
    <?xml version="1.0" encoding="utf-8"?>
    <configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
        <system.web>
            <compilation debug="true" />
            <pages enableViewState="false" />
        </system.web>
    </configuration>
  2. На уровне страницы, добавив в директиву @ Page параметр EnableViewState="false" (в коде свойство Page.EnableViewState = false )
  3. На уровне элемента управления, добавив в дескриптор элемента атрибут EnableViewState="false" (в коде свойство Элемент.EnableViewState = false )

Если более общая настройка сохранения состояния вида выключена, а для каких-то страниц или элементов управления ее нужно включить, то в соответствующее место следует добавить атрибут EnableViewState="true".

Защита информации в состоянии вида

Состояние вида передается клиенту системой ASP.NET в скрытых полях частично зашифрованным. Но это шифрование поверхностное, чтобы не требовало много процессорного времени. При желании злоумышленник может частично восстановить и прочитать эту информацию.