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

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

Строки запроса

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

  1. Информация является видимой для пользователя и доступна для вмешательства с его стороны. В результате страница может получить такие данные, от которых она не имеет защиты
  2. Информация должна кодироваться допустимыми для URL символами
  3. Броузеры устанавливают ограничение на длину URL, которая должна быть в пределах 1-2 Кб. Поэтому в строку запроса нельзя помещать большое количество информации
  4. Форма отправляющей страницы должна использовать метод передачи GET вместо POST
  5. Формирование строки запроса и извлечение из нее информации программист выполняет вручную

Отправляющая запрос страница инициирует передачу либо с помощью гиперссылки (элемент HyperLink ), либо с помощью кнопки Submit, в обработчик которой вставлен код Response.Redirect(URL). Для извлечения информации из строки запроса на адресуемой (целевой) странице используется встроенный в нее объект-словарь Request.QueryString.

Упражнение 6

  • Добавьте к проекту страницу без файла отделенного кода с именем SourceQueryString.aspx и назначьте ее стартовой
  • Добавьте внутрь контейнера <div></div> дескриптор строки-заголовка
    <h1 style="color: Red">Введите учетную запись</h1>
  • Дополните открывающий дескриптор <div> стилем центрирования
    <div style="text-align: center">
  • Создайте на Web-форме позиционирующую таблицу размером 3x2 и поместите в ее ячейки из вкладки Standard панели Toolbox серверные элементы с настройками согласно таблице
Таблица свойств элементов управления страницы SourceQueryString.aspx
Элемент Свойство
Label ID="Label1"
Text="Имя:"
TextBox ID="Name"
Label ID="Label2"
Text="Пароль:"
TextBox ID="Password"
TextMode="Password"
Button ID="Button1"
Text="Отправить"

Интерфейс страницы в режиме проектирования будет таким


  • Переведите страницу в режим Design и двойным щелчком на элементе Button1 создайте для него обработчик. Заполните обработчик следующим кодом
protected void Button1_Click(object sender, EventArgs e)
{
    string Url = "TargetQueryString.aspx?Name="
                            + Server.UrlEncode(Name.Text)
                            + "&Password="
                            + Server.UrlEncode(Password.Text);
    this.Response.Redirect(Url);
    
    // То же самое, только с прямой переадресацией
    // this.Server.Transfer(Url);
}

Кнопка будет инициировать обратную отсылку, а ее обработчик сформирует адрес целевой страницы со значениями параметров, снятых с элементов текстовых полей. Перед включением в строку адреса введенных пользователем значений мы применяем URL-кодирование, преобразуя тем самым ввод в допустимые символы. К сожалению, строку адреса приходится формировать вручную.

  • Переведите страницу в режим Design и двойным щелчком создайте в кодовой части обработчик Page_Load(). Заполните обработчик кодом, восстанавливающий состояние текстового поля Name сохраненным в строке запроса значением
protected void Page_Load(object sender, EventArgs e)
{
    if (this.Request.QueryString["Name"] != null && !this.IsPostBack)
        Name.Text = this.Request.QueryString["Name"];
}

Страница SourceQueryString.aspx, отправляющая строку запроса, готова. Вот ее полный код

<%@ Page Language="C#" %>
    
<script runat="server">
    
    protected void Button1_Click(object sender, EventArgs e)
    {
        string Url = "TargetQueryString.aspx?Name="
                                + Server.UrlEncode(Name.Text)
                                + "&Password="
                                + Server.UrlEncode(Password.Text);
        this.Response.Redirect(Url);
        
        // То же самое с прямой переадресацией
        // this.Server.Transfer(Url);
    }
    
    protected void Page_Load(object sender, EventArgs e)
    {
        if (this.Request.QueryString["Name"] != null && !this.IsPostBack)
            Name.Text = this.Request.QueryString["Name"];
    }
</script>
    
<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">
            <h1 style="color: Red">
                Введите учетную запись</h1>
            <table border="0" width="100%">
                <tr>
                    <td style="text-align: right; width: 412px;">
                        &nbsp;<asp:Label ID="Label1" runat="server" Text="Имя:" />
                    </td>
                    <td>
                        &nbsp;<asp:TextBox ID="Name" runat="server" />
                    </td>
                </tr>
                <tr>
                    <td style="width: 412px; text-align: right">
                        &nbsp;<asp:Label ID="Label2" runat="server" Text="Пароль:" />
                    </td>
                    <td>
                        &nbsp;<asp:TextBox ID="Password" runat="server" TextMode="Password" />
                    </td>
                </tr>
                <tr>
                    <td colspan="2" style="text-align: center">
                        &nbsp;<asp:Button ID="Button1" runat="server" Text="Отправить" 
                        OnClick="Button1_Click" />
                    </td>
                </tr>
            </table>
        </div>
    </form>
</body>
</html>

Теперь нужно создать принимающую запрос (целевую) страницу. На целевой странице значения поступивших параметров, извлекаемые из строки запроса, следует предварительно URL-раскодировать. Затем можно принять решение, что делать с поступившими данными.

  • Создайте страницу с совмещенным кодом и именем TargetQueryString.aspx
  • Заполните страницу следующим кодом
<%@ Page Language="C#" %>
    
<script runat="server">
    
    protected void Page_Load(object sender, EventArgs e)
    {
        // Критерии оценки зарегистрированного пользователя
        const string NAME = "USER", PASSWORD = "ROOT";
    
        // Извлекаем и раскодируем поступившие данные из строки запроса
        string name = this.Request.QueryString["Name"];
        name = this.Server.UrlDecode(name);
        string password = this.Request.QueryString["Password"];
        password = this.Server.UrlDecode(password);
    
        // Создаем текстовую метку для отображения решения
        Label label = new Label();
        form1.Controls.Add(label);
    
        // Резервируем место для размещения гиперссылки
        PlaceHolder placeHiperLink = new PlaceHolder();
        form1.Controls.Add(placeHiperLink);
    
        // Создаем муляж кнопки
        Button button = new Button();
        form1.Controls.Add(button);
    
        // Анализируем данные и принимаем решение
        StringBuilder message = new StringBuilder();
        if (name.ToUpper() == NAME && password.ToUpper() == PASSWORD)
        {
            // Просто выведем хвалебное приветствие 
            message.Append("<h1 style=\"color: Red\">");
            message.Append("Приветствуем Вас, дорогой " + name + "!");
            message.Append("</h1>");
    
            // Отключаем у кнопки способность инициировать отсылку
            // Лень посылать дальше зарегистрированного пользователя 
            button.PostBackUrl = "javascript: void(0)";
            button.Text = "Дальше >";
    
            // Добавляем в зарезервированное место гиперссылку
            HyperLink link = new HyperLink();
            placeHiperLink.Controls.Add(link);
            link.Text = "< Назад";
            link.NavigateUrl = "~/SourceQueryString.aspx?"
                + "Name=" + name;
    
            // Добавляем в зарезервированное место пробелы
            Label lblSpace = new Label();
            placeHiperLink.Controls.Add(lblSpace);
            lblSpace.Text = "&nbsp;&nbsp;&nbsp;&nbsp;";
        }
        else
        {
            // Поругаем и отправим на повторную регистрацию
            message.Append("<h1>");
            message.Append("Вы неопознаны!<br />Повторите регистрацию...");
            message.Append("</h1>");
    
            button.PostBackUrl = "~/SourceQueryString.aspx?"
                + "Name=" + name;
            button.Text = "< Назад";
        }
    
        // Выводим сформированное сообщение
        label.Text = message.ToString();
    }
</script>
    
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    </form>
</body>
</html>

Обратите внимание, что интерфейсная часть целевой страницы совершенно пустая - все создается динамически.

  • Запустите страницу SourceQueryString.aspx на выполнение и убедитесь, что механизм межстраничного обмена информацией через строку запроса работает

Страница TargetQueryString.aspx на клиенте при наведении курсора мыши на гиперссылке будет выглядеть так

Межстраничная обратная отсылка данных

В классах кнопочных элементов управления Button, ImageButton и LinkButton имеется свойство PostBackUrl, позволяющее сразу адресоваться к целевой странице с доступом в ней ко всем данным текущей страницы. Свойству PostBackUrl кнопки обратной отсылки присваивается строка с URL целевой страницы, которая и будет загружена на выполнение по щелчку пользователя на этой кнопке. При этом на целевой странице, благодаря ее свойству PreviousPage, будет полностью доступен объект страницы, инициировавшей обратную отсылку.

Идея реализации механизма межстраничной отсылки достаточно проста. Любая страница на этапе описания является классом (инструкцией) с именем, равном имени страницы, которая при загрузке в память сервера превращается в объект (экземпляр класса), адресуемый средой исполнения. Исполняемый объект проходит все необходимые этапы жизни, начиная с инициализации элементов управления, корректировкой состояния, выполнением обработчиков, и заканчивая генерацией HTML-кода (рендерингом).

То же самое происходит и со страницей, загруженной по кнопке с ненулевым свойством PostBackUrl. Она также проходит все начальные стадии жизни, включая выполнение обработчиков. Непосредственно перед генерацией HTML-кода выполнение исходной страницы прерывается, но она продолжает оставаться в памяти сервера. Одновременно запускается объект целевой страницы, которому в свойство PreviousPage среда исполнения записывает адрес объекта первой страницы.

Теперь код целевой страницы может адресоваться к общедоступным данным исходной страницы, но рендеринг для клиента будет генерироваться только второй страницей. Когда целевая страница заканчивает свой цикл жизни, вместе с ней из памяти выгружается и исходная страница. Для того, чтобы закрытые или защищенные члены класса исходной страницы стали доступными в классе целевой страницы, их нужно обернуть в общедоступные свойства или функции доступа.

Рассмотренная межстраничная связь может быть реализована не только как "один к одному", но и в других сочетаниях: "один ко многим", "многие к одному" или "многие ко многим". Множественность на исходной странице может быть организована программным формированием значения свойства PostBackUrl в зависимости от выбранных на этой странице предпочтений. Множественность на целевой странице реализуется проверкой того, к какому типу (к какой странице) относится записанный в свойство PreviousPage объект.

Межстраничная обратная отсылка целевой страницы может быть инициирована не только по щелчку на кнопке с ненулевым значением свойства PostBackUrl, но и в любом месте кода вызовом соответствующей перегрузки метода

public void Page.Server.Transfer(string path, bool preserveForm)

где

  • path - вызываемая целевая страница
  • preserveForm - флаг передачи в целевую страницу данных QueryString и Form

Оптимальным будет вызов

Server.Transfer(Url, true);