Эффективное использование ASP.NET WebForms 4.0: ViewState

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

Управление ViewState

Для более гибкого управления механизмом ViewState в ASP.NET 4.0 были добавлены дополнительные рычаги, позволяющие разработчикам эффективнее использовать сохранение состояния страниц.

Ранее существовал только один способ управления сохранением состояния страниц – свойство EnableViewState у класса страницы. Это свойство позволяло централизованно включать или выключать механизм сохранения состояния для каждой из страниц. Однако, наиболее общим сценарием при разработке веб-приложений является сценарий, когда вам требуется сохранить состояние определенных элементов на страницы, но не всей страницы сразу. В ASP.NET предыдущих версий выполнить это было довольно сложно, поскольку при выключении состояния для всей страницы, не было возможности включить его для определенных элементов.

Для устранения этого ограничения в ASP.NET 4.0 было добавлено новое свойство ViewStateMode, которое позволяет гораздо лучше управлять состоянием страниц. Свойство ViewStateMode может принимать три значения:

  • Disabled – запрещает использование механизма сохранения состояния для элемента и по умолчанию запрещает сохранение для всех вложенных в него элементов;
  • Enabled – позволяет использование механизма сохранения состояния для элемента и по умолчанию позволяет сохранение для всех вложенных в него элементов;
  • Inherit – указывает на то, что управление механизмом сохранения состояния должно наследоваться от родительского элемента.

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

На примере ниже для страницы значение ViewStateMode установлено в “Disabled”, что означает запрет на сохранение состояния по умолчанию для всех элементов страницы.

 <%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
    CodeBehind="Default.aspx.cs" Inherits="WebApplication1._Default" ViewStateMode="Disabled" %>
 
<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <p>
        <asp:Label runat="server" ID="FirstLabel" ViewStateMode="Enabled" 
            Text="Первое сообщение (ViewStateMode = Enabled)."></asp:Label>
 
        <asp:Label runat="server" ID="SecondLabel" ViewStateMode="Disabled" 
            Text="Первое сообщение (ViewStateMode = Disabled)."></asp:Label>
 
        <asp:Button runat="server" Text="Отправить" />
    </p>
</asp:Content>

Однако, для метки FirstLabel значение ViewStateMode установлено в "Enabled", что говорит о нашем желании использовать ViewState для этого элемента. Теперь у двух меток будет разное поведение при изменении их значения. На примере ниже мы изменяем значение меток при первой загрузки страницы.

 protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        FirstLabel.Text = "Привет, мир!";
        SecondLabel.Text = "Привет, мир!";
    }
}

После этого, при первой загрузки страницы мы увидим на странице обновленные метки.

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

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

Использование механизма ControlState

Существует способ использовать ViewState и при установленном значении EnableViewStatу = False для всей страницы, эта техника основывается на использовании механизма сохранения состояния ControlState. И если ViewState выключить можно, то ControlState — нет.

Рассмотрим пример:

 [Serializable]     
struct PageStateStruc     
{         
    public FormState CurrentState;
    public int? CurrentResume;
    public int CurrentSection;
}     
PageStateStruc PageState;
    
protected override void OnInit(EventArgs e)
{
    Page.RegisterRequiresControlState(this);
    base.OnInit(e);
}      
    
protected override object SaveControlState()     
{         
    return PageState;     
}      
    
protected override void LoadControlState(object savedState)     
{         
    PageState = (PageStateStruc)savedState;     
}

Здесь определяется некая структура данных PageStateStruc, экземпляр которой мы будем сохранять. Обратите внимание на атрибут Serializable, который для используемой структуры обязателен. Тут же определяется экземпляр структуры PageState.

Далее, в обработчике OnInit вызывается метод RegisterRequiresControlState, который регистрирует текущую страницу как элемент управления, ControlState которого следует сохранять. Вместо this можно указать любой пользовательский элемент управления. Рекомендуется осуществлять вызов RegisterRequiresControlState именно в OnInit.

Завершают картину два перегруженных метода SaveControlState и LoadControlState, которые, как это видно, просто осуществляют загрузку и выгрузку необходимых данных. Вызов этих методов asp.net берет на себя.

Это все, данные PageState между запросами к странице будут автоматически сохраняться. По сути, для сохранения данных между вызовами страницы нам необходимо только определить вид данных и описать, как эти данные необходимо сохранять/загружать. Остальное делает инфраструктура ASP.NET.

Использование механизма Trace для слежения за ViewState

При разработке сложных веб-страниц со множеством элементов управления часто возникает необходимость отследить поведение страницы и параметры использования ViewState. В ASP.NET существует простой способ профилирования страниц – Trace. Просто добавьте в определение страницы значение Trace = True:

 <%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
    CodeBehind="Default.aspx.cs" Inherits="WebApplication1._Default" ViewStateMode="Disabled" 
    Trace="true" %>

Теперь после загрузки страницы вы будете получать подробную информацию по всем элементам страницы, в том числе объем ViewState используемый элементами: