Проектирование и разработка веб-приложений на основе технологий Microsoft

Технология ASP.Net : Управление состоянием

Показывать лекцию целиком

В ASP.Net предоставляет два типа управления состоянием веб – приложения: на клиенте и на сервере. Каждый из этих типов обладает отличительными особенностями, с которыми мы и познакомимся в ходе лекции.

Управление состоянием веб – приложения на стороне клиента

Преимущества хранения информации на стороне клиента:

  • Лучшая масштабируемость. При управлении состоянием на сервере каждый подключившийся к веб-серверу клиент занимает часть ресурсов сервера. Если сайт одновременно посещают сотни и тысячи пользователей, для хранения их состояния им потребуется много памяти, которая может стать узким местом. Устранить его можно, переложив управление данными состояния на пользователей;
  • Поддержка множества веб-серверов. При управлении состоянием на клиенте обработку поступающих запросов можно распределить среди множества веб-серверов, не модифицируя код приложения, так как клиент предоставляет веб-серверу всю необходимую информацию. При управлении состоянием на сервере клиент в середине сеанса может обратится к другому серверу, но у того может не оказаться доступа к состоянию клиента. При управлении состоянием на сервере с использованием группы серверов необходима интеллектуальная балансировка нагрузки (пересылающая запросы одного клиента одному и тому же серверу) либо централизованное управление состоянием (когда состояние хранится в центральной базе данных, доступной всем веб-серверам).
  • Методы хранения сведений на стороне клиента, необходимых для управления состоянием:

  • ViewState или состояние отображения – отслеживает значения элементов управления;
  • ControlState или состояние элемента управления – применяется при создании пользовательских элементов управления, как правило, используется для корректной работы пользовательского ЭУ, даже в случае отключения ViewState ;
  • Скрытые поля – данные сохраняются в HTML – форме и являются невидимыми для браузера;
  • Cookie – файлы – эти файлы хранят введенные в браузер значения, которые браузер отсылает на сервер при последующих запросах данной страницы;
  • Строки запроса – сохраняют значения в составе URL.
  • ViewState

    View State —называется способ хранения данных о состоянии страницы в скрытом поле формы на самой странице. Данные из скрытого поля используются, чтобы для конкретного клиента установить состояние серверных объектов, формирующих страницу.

    Чтобы отключить состояние отображения веб-элемента управления, присвойте его свойству EnableViewState значение False. Это ускорит обработку данных на сервере и уменьшит размер страницы.

    Также можно откоючить ViewState и на уровне страницы:

    <%@ Page EnableViewState="false" %>

    Важно следующее: по – умолчанию, состояние отображение включено у каждого элемента управления, что не всегда хорошо. Прежде всего, при использовании ViewState страница становится "тяжелее", как для обработки, так и для передачи клиенту, из-за дополнительного объема. Далее, дополнительная нагрузка связана с формированием и разбором данных скрытого поля ViewState. И, наконец, для обработки View State все-таки требуется память на сервере.

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

    В случае, если в ViewState планируется хранить конфиденциальные данные (чего, строго говоря, следует, при возможности, избегать), можно включить шифрование

    Чтобы включить шифрование состояния отображения в приложении, в файле Web.config присвойте атрибуту <pages viewStateEncryptionMode> значение Always:

    <configuration>
    <system.web>
    <pages viewStateEncryptionMode="Always"/>
    </system.web> </configuration>

    Запись данных ViewState

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

    if (ViewState["lastVisit"] != null)
    {
      Labell.Text = (string)ViewState["lastVisit"];
    }
    else
    {
      Labell.Text = "lastVisit ViewState not defined.";
    }
    ViewState.Add("lastVisit", DateTime.Now.ToString());

    Чтение данных ViewState

    В следующем примере после проверки наличия объекта ViewState, отображается дата последнего посещения страницы пользователем:

    // Проверка наличия объекта ViewState 
    if (ViewState["lastVisit"] != null)
    {
      Labell Text = ((DateTime)ViewState["lastVisit"]).ToString();
    }
    else
    {
      Labell.Text = "lastVisit ViewState not defined";
    }
    ViewState["lastVisit"] = DateTime.Now;

    ControlState

    Обычно ControlState используется для того, чтобы элемент управления работал корректно в случае EnableViewState = false. Если на работу вашего ЭУ никак не влияет ViewState – то нет смысла применять ControlState.

    В следующем примере кода демонстрируется, каким образом класс, производный от класса http://msdn.microsoft.com/ru-ru/library/system.web.ui.pagestatepersister.controlstate.aspx

    public override void Load()
    {
        Stream stateStream = GetSecureStream();
        StreamReader reader = new StreamReader(stateStream);
        IStateFormatter formatter = this.StateFormatter;
        string fileContents = reader.ReadToEnd();
        Pair statePair = (Pair)formatter.Deserialize(fileContents);
        ViewState = statePair.First;
        ControlState = statePair.Second;
        reader.Close();
    
        stateStream.Close();
    }

    Скрытые поля

    Преимущества использования скрытых полей:

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

  • Потенциальная угроза безопасности. Скрытое поле может быть подделано. Сведения в скрытом поле можно увидеть, если источник выходных данных страницы просматривается напрямую, что создает потенциальную угрозу безопасности.
  • сложные типы данных. Скрытые поля содержат поле с одним строковым значением, в которое помещается информация. Для сохранения нескольких значений необходимо реализовать разделенные строки и код, анализирующий эти строки.
  • Вопросы производительности. Поскольку скрытые поля сохраняются на самой странице, при сохранении больших значений процесс отображения и отправки страницы может замедлиться.
  • Ограничения размера хранилища. Если объем данных в скрытом поле становится слишком большим, то некоторые прокси-серверы и брандмауэры будут запрещать доступ к странице, содержащей эти данные.
  • Элемент управления HiddenField хранит единственную переменную в свойстве Value, он должен быть явно добавлен на страницу. Скрытые поля хранят информацию для одной страницы, поэтому бесполезно сохранять в них сеансовые данные. При использовании скрытых полей страницы должны отправляться на сервер с помощью HTTP-метода POST (по щелчку кнопки), а не HTTP GET (по щелчку ссылки).

    Пример сохранения данных:

    HiddenFieldl.Value = control.Value.ToString();

    Свойство HiddenField. Value имеет тип String, поэтому перед его установкой требуется преобразовать данные в тип String.

    Cookie – файлы

    Cookie — это текстовая строка, включаемая в запросы и ответы HTTP (Hypertext Transfer Protocol). Файлы cookie используются для сохранения данных о пользователе, посещающем различные страницы веб-узла или возвращающемся на веб-узел спустя некоторое время. В этой статье представлены сведения о файлах cookie.

    Одно из главных назначений файлов cookie — предоставлять удобное средство экономии времени. Файлы cookie позволяют сообщить веб-узлу, что пользователь вернулся на конкретную страницу. Например, при обращении к личной веб-странице или при вводе регистрационных данных файлы cookie помогают серверу восстановить сведения, связанные с текущим пользователем. Это дает возможность упростить процесс сохранения персональных данных (например, адреса для доставки счетов или товара и т. д.). При повторном обращении на веб-узел предоставленные ранее сведения могут быть восстановлены, что облегчает повторное использование ранее выбранных возможностей данного узла. Ниже приведены примеры использования файлов cookie.

  • Если пользователь Интернет-магазина ранее указывал адрес для доставки счетов или товара, вместо повторного ввода этих данных можно указать пароль, позволяющий автоматически заполнить соответствующие поля в форме заказа.
  • Файл cookie может содержать сведения о выбранных ранее интересующих темах, которые будут отображаться при каждом посещении веб-узла данным пользователем. Например, на странице с новостями можно указать только интересующие пользователя темы новостей http://support.microsoft.com/kb/260971/ru
  • Чтение и запись Cookie

    Следующий пример кода (обработчика события Page_Load ) демонстрирует установку и чтение значения cookie с именем "lastVisit", содержащее значение текущего времени. Если у пользователя cookie уже установлен, код отобразит время последнего посещения страницы пользователем в элементе управления Labe1l. Если при посещении пользователем страницы из предыдущего примера cookie еще не установлен, код покажет сообщение "No value defined"

    if (Request.Cookies["lastVisit"] != null)
    {
      Server.HtmlEncode(Request.Cookies["lastVisit"].Value);
    }
    else
    {
      Labell.Text = "No value defined";
    }
    // Установить cookie для следующего визита
    Response.Cookies["lastVisit"].Value = DateTime.Now.ToString();
    Response.Cookies["lastVisit"].Expires = DateTime.Now.AddDays(1);

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

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

    Строки запроса — простой, но ограниченный механизм хранения информации о состоянии между запросами страниц. Например, в строке запроса легко передать количество товара со страницы описания на страницу оформления заказа. Некоторые браузеры и устройства ограничивают длину URL 2083 символами. Другое ограничение состоит в необходимости отправки страницы командой HTTP GET, чтобы значения из строки запроса были доступны для обработки. Следовательно, запросы нельзя добавлять в целевые URL кнопок на формах.

    Значения из строк запросов должны всегда проверяться на допустимость.

    Для чтения значения строки запроса необходимо обратиться к набору Request.QueryStrings, как к cookie.

    следующий код показывает значения параметров user, prefs и page из строки запроса в элементе управления Label1:

    Labell.Text = "User: " +
       Server.HtmlEncode(Request.QueryString["user"]) + ", Prefs: " + 
       Server.HtmlEncode(Request.QueryString["prefs"]) + ", Page: " + 
       Server.HtmlEncode(Request.QueryString["page"]);

    Необходимо всегда кодировать cookie и значения в строке запроса с помощью Server. Html Encode перед отображением значения на HTML-страницах. Server. HtmlEncode заменяет HTML-код специальными символами, которые веб-браузер в состоянии только отображать, но не обрабатывать.

    Управление состоянием на стороне сервера:

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

    Хранение информации на сервере имеет следующие преимущества:

  • Безопасность. Информация управления состоянием на клиенте может быть похищена с клиентского компьютера или перехвачена в пути, а также она уязвима к модификации злоумышленниками. Следовательно, ни в коем случае не используйте управление состоянием на клиенте для хранения конфиденциальной информации, такой как пароль, уровень доступа или состояние авторизации;
  • Снижение нагрузки на сеть. При транспортировке больших объемов данных состояния между клиентом и сервером создается значительная нагрузка на канал связи и увеличивается время загрузки страницы, что чревато ростом расходов и снижением масштабируемости. Пересылка больших объемов данных негативно сказывается на эффективности мобильных клиентов, обычно подключенных через медленные каналы связи. Следовательно, громоздкую информацию управления состоянием (более 1 Кб) лучше хранить на сервере.
  • Параметры управления состоянием на стороне сервера, поддерживаемые ASP.NET:

  • Состояние приложения
  • Состояние сеанса
  • Свойства профиля
  • Поддержка базы данных
  • Состояние приложения

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

    Состояние приложения хранится в объекте-словаре Application (экземпляре класса HttpApplicationState ), который представляет собой набор пар "ключ—значение". К нему можно добавлять специфичную для приложения информацию, где она сохранится между запросами страниц. После введения такой информации в состояние приложения сервер обработает ее без участия клиента, причем она становится недоступной клиенту. Состояние приложения — один из лучших механизмов хранения информации, не специфичной для пользователей. Он позволяет всем страницам обращаться к одной копии данных, хранящихся в одной области памяти, а не к множеству отдельных копий.

    Теоретически, любой может обратиться к объекту Application, поэтому хранящаяся в нем информация о пользователе уязвима с точки зрения безопасности.

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

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

    Использование состояния приложения:

    Application["Message"] = "Some string";
    Application["AppStartTime"] = DateTime.Now;
    string s = (string)Application["Message"];
    DateTime startTime = (DateTime)Application["AppStartTime"];

    Поскольку значения контейнера Application доступны из всех страниц, то в случае одновременного обращения нескольких потоков к одному значению возникает проблема синхронизации. В качестве решения используются два метода: Lock() и Unlock(). Вызов метода Lock заставляет ASP.NET блокировать все попытки доступа любых других потоков к любой информации из Application. Блокировка снимается вызовом метода Unlock.

    Application.Lock();
    Application["number"] = (int)Application["number"] + 1;
    Application.UnLock();

    Одним из недостатков Application является неограниченное время жизни его объектов. Т.е. значения, записанные в эту коллекцию, будут в ней существовать до тех пор, пока они не будут явно удалены (методы Remove, RemoveAll, RemoveAt, присвоение null ).

    // удаление SomeGlobalCounter из Application методом Remove
    Application.Remove("SomeGlobalCounter");
    // удаление SomeGlobalCounter из Application присвоением null
    Application["SomeGlobalCounter"] = null;

    В ином случае они будут существовать до завершения работы приложения либо перезагрузки веб-сервера.

    Состояние сеанса

  • ASP.NET предоставляет состояние сеанса, доступное как класс HttpSessionState, в качестве метода хранения специфичной для сеанса информации, видимой только в пределах сеанса. Состояние сеанса ASP.NET определяет запросы, полученные от обозревателя в течение ограниченного периода времени (сеанса), и предоставляет возможность сохранения значений переменных в течение этого сеанса.
  • В состоянии сеанса можно сохранять специфичные для сеанса значения и объекты; после этого управление состоянием сеанса переходит серверу, и оно становится доступным обозревателю или клиентскому устройству.

    Контейнер Session похож на Application, с той лишь разницей, что для каждого пользователя приложения создается своя собственная сессия со своими собственными значениями. Для идентификации пользователей ASP.NET использует 120-битный ключ, именуемый SessionID и состоящий только из ASCII-символов, которые допустимы для использования в URL. В зависимости от настроек веб-приложения, этот ключ сохраняется либо в Cookie либо включается как часть URL.

    Пример:

    Session["Message"] = "My string";
    Session["SessionStartTime"] = DateTime.Now;
    string s = (string)Session["Message"];
    DateTime startTime = (DateTime)Session["SessionStartTime"];

    Коллекция StaticObjects является read-only коллекцией, ее элементы определяются в файле Global.asax с помощью тега <object runat="server" scope="session">.

    <object runat="server" scope="session" 
                id="SessionStr" class="System.Text.StringBuilder"/>

    Отключение состояния сеанса

    Если состояние сеанса не используется, можно повысить производительность, отключив его для всего приложения путем присваивания свойству sessionState mode в файле Web.config значения Off:

    <configuration>
      <system.web> 
        <sessionState mode="off"/>
      </system.web> 
    </configuration>

    Для отключения состояния сеанса на отдельной странице приложения установите страничную директиву EnableSessionState в False.

    Свойства профиля

    Для использования профилей сначала нужно включить профили, изменив файл конфигурации веб-приложения ASP.NET. В составе конфигурации указывается поставщик профилей — это базовый класс, отвечающий за низкоуровневые задачи хранения и извлечения данных профилей. Можно использовать поставщик профилей, входящий в состав платформы .NET Framework, который хранит данные профилей в SQL Server, или создать и использовать свой собственный поставщик профилей.

    Функция профилей настраивается путем определения списка свойств, значения которых необходимо поддерживать. Например, может понадобиться хранить почтовый индекс пользователя, чтобы приложение могло предоставлять ему региональные сведения — например, прогноз погоды. В файле конфигурации для этого потребуется определить свойство профиля с именем PostalCode. Раздел profile файла конфигурации может выглядеть следующим образом:

    <profile>
      <properties>
        <add name="PostalCode" />
      </properties>
    </profile>

    При запуске приложения платформа ASP.NET создает класс ProfileCommon, который создается динамически путем наследования от класса ProfileBase. В динамическом классе ProfileCommon представлены свойства, созданные по определениям свойств профиля, указанным в конфигурации приложения. Экземпляр этого динамического класса ProfileCommon затем задается в качестве значения свойства Profile текущего контекста HttpContext и будет доступен на страницах приложения.

    В приложении необходимо получить значение или значения, которые необходимо сохранить, и занести их в определенные ранее свойства. Например, начальная страница приложения может содержать текстовое поле, в котором пользователь указывает почтовый индекс. Когда пользователь вводит почтовый индекс, свойство Profile получает значение для текущего пользователя, как показано в следующем примере:

    Profile.PostalCode = txtPostalCode.Text;

    При задании значения для Profile.PostalCode значение автоматически сохраняется для текущего пользователя. Нет необходимости писать код для определения того, кем является текущий пользователь, или явно сохранять значение в базе данных — эти задачи выполняет функция профилей.

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

    weatherInfo = GetWeatherInfo( Profile.PostalCode );

    Нет необходимости определять, кем является пользователь, или выполнять поиск в базе данных. Простое считывание значения свойства из профиля приводит к тому, что платформа ASP.NET выполняет необходимые действия для идентификации текущего пользователя и поиска значения в постоянном хранилище профилей http://msdn.microsoft.com/ru-ru/library/2y3fs9xs.aspx

    Дополнительные материалы

  • http://www.gotdotnet.ru/blogs/abasyuk/6536/
  • http://msdn.microsoft.com/ru-ru/library/z1hkazw7.aspx
  • Вернуться к учебному плану