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

Ниже перечислены некоторые проблемы веб-приложений и то, как они решаются с помощью кэширования.

Производительность

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

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

Масштабируемость

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

Доступность

Веб-приложения обычно представляют собой данные, получаемые с сервера базы данных. База данных может располагаться на удаленной системе. В случае обрыва связи между веб-сервером и сервером базы данных веб-приложение не сможет обслуживать запросы пользователей. Веб-приложения, использующие кэширование, извлекают данные из базы данных, а затем сохраняют их в кэше. При последующих запросах данные извлекаются из кэша. Поэтому даже в случае недоступности сервера базы данных веб-приложение может обслуживать запросы на вывод данных, используя кэш. Однако следует помнить, что для обновления кэша веб-приложению придется подключиться к серверу базы данных.

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

  • Снижение затрат на обработку при визуализации «сырых» данных, извлеченных из базы данных.

  • Уменьшение числа обращений к диску, так как большая часть кэшированных данных хранится в оперативной памяти.

ASP.NET поддерживает кэширование данных, а также веб-страниц. Механизм кэширования данных приложений (Data Caching) позволяет кэшировать данные, а механизм кэширования вывода страниц (Output Caching) — веб-страницы.

Кэширование данных приложений

В этом случае веб-приложение кэширует данные, такие как экземпляр DataSet, экземпляр DataTable или статические данные, например названия стран. Такие данные хранятся в кэше приложения. Каждому веб-приложению предоставляется своя копия кэша приложений. Кэш приложения создается и поддерживается с помощью класса Cache. Элемент данных добавляется в кэш приложения с помощью метода Add() класса Cache.

Синтаксис

public Object Add(string key, Object value, CacheDependency dependencies, DateTime absoluteExpiration, TimeSpan slidingExpiration, CacheItemPriority priority, CacheItemRemovedCallback onRemovedCallback)

Здесь:

  • key — имя, которое будет связано со значением.

  • value соответствует значению элемента.

  • dependencies представляют экземпляр, от которого зависит обновление элемента кэша.

  • absoluteExpiration — время, по истечении которого элемент в кэше прекращает свое существование и удаляется из кэша; его можно отключить с помощью поля Cache.NoAbsoluteExpiration.

  • slidingExpiration — это интервал времени между временем последнего обращения к элементу и временем прекращения его существования; его можно отключить с помощью поля Cache.NoSlidingExpiration.

  • priority — приоритет элемента; элементы с более низким приоритетом удаляются первыми.

  • onRemovedCallback — делегат, который вызывается при удалении элемента из кэша приложения.

Ниже показан код для добавления типизированного экземпляра DataTable с именем dtState в кэш приложения.

DataSet1 dsetState = new DataSet1();
DataSet1TableAdapters.StateTableAdapter taState = new DataSet1TableAdapters.StateTableAdapter();
DataSet1.StateDataTable dtState = dsetState.State;
taState.Fill(dtState);
if (Cache[“StateDataTable”] == null) {
    Cache.Add(“StateDataTable”, dtState, null, DateTime.Now.AddSeconds(60), TimeSpan.Zero, CacheItemPriority.Default, null);
}

Набор данных dsetState, используемый в этом коде, представляет собой типизированный набор данных, используемый для хранения данных из базы данных YellowPages. taState — типизированный экземпляр TableAdapter — используется для заполнения типизированной таблицы DataTable с именем dtState записями из таблицы State. Таблица данных dtState добавляется в кэш с помощью метода Add(). Обратите внимание, что аргументы для CacheDependency и CacheItemRemovedCallback установлены на null. Поэтому метод Add() будет кэшировать экземпляр dtState с именем StateDataTable в течение 60 секунд с текущего момента времени. Элемент StateDataTable кэшируется с приоритетом по умолчанию. В таблице ниже приведены списки различных значений для перечисления CacheItemPriority.

Члены

Описание

AboveNormal

При освобождении памяти системы с поддержкой кэширования элементы кэша с данным приоритетом с меньшей вероятностью будут удалены из кэша по сравнению с элементами, имеющими приоритет Normal.

BelowNormal

При освобождении памяти системы с поддержкой кэширования элементы кэша с данным приоритетом с большей вероятностью будут удалены по сравнению с элементами, имеющими приоритет Normal.

Default

Этот приоритет присваивается элементам кэша по умолчанию.

High

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

Low

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

Normal

При освобождении памяти системы с поддержкой кэширования элементы кэша с данным приоритетом удаляются только после удаления элементов кэша с приоритетами Low и BelowNormal.

NotRemovable

При освобождении памяти системы с поддержкой кэширования элементы кэша с данным приоритетом не удаляются.

Кэширование вывода страниц

ASP.NET обеспечивает кэширование веб-страниц с помощью механизма кэширования вывода страниц. Активация кэширования страницы выполняется с помощью директивы @OutputCache. Эта директива прописывается в верхней части страницы, которую необходимо кэшировать. Ниже показан код для кэширования веб-страницы на 60 секунд.

<%@ Page Language=”C#” AutoEventWireup=”true”  CodeFile=”Default.aspx.cs”
Inherits=”_Default” %>
<%@ OutputCache Duration=”60” VaryByParam=”None” %>
<form id=”form1” runat=”server”>
    <div> Time in cached page:
        <asp:Label ID=”lblTime” runat=”Server”></asp:Label>
    </div>
</form>

Веб-страница в приведенном коде использует элемент управления Label с именем lblTime для отображения текущего времени. Свойство Text этого элемента управления задается в обработчике события Page_Load, как показано ниже.

Protected void Page_Load(object sender, EventArgs e) {
    lblTime.Text = DateTime.Now.ToLongTimeString();
}

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

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

Послекэшевая подстановка

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

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

Для реализации послекэшевой подстановки с помощью элемента управления Substitution нам потребуется следующее.

Статический метод

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

public static String GetTime(HttpContext context) {
    return DateTime.Now.ToLongTimeString();
}

Метод GetTime() возвращает текущее системное время. Обратите внимание, что статический метод должен возвращать String и принимать параметр типа HttpContext. Этот метод должен быть определен в файле .aspx или в файле вынесенного кода (code-behind) веб-страницы.

Элемент управления Substitution

Элемент управления Substitution создается путем перетаскивания его из панели инструментов на веб-форму. Этот элемент управления размещается в том месте, где должно выводиться динамическое содержимое. Далее элемент управления связывается со статическим методом GetTime() с помощью свойства MethodName. Во время выполнения элемент управления Substitution заменяется строкой, возвращаемой статическим методом GetTime().

Код, приведенный ниже, представляет собой измененную версию ранее рассмотренного кода.

<%@ page language=”C#” AutoEventWireup=”true” CodeFile=”Default.aspx.cs” Inherits=”_Default” %>
<%@ OuputCache Duration=”60” VaryByParam=”None” %>
<form id=”form1” runat=”server”>
<div>

Время на кэшированной странице

<asp:Label ID=”lblTime” runat=”server”></asp:Label>
<br />
<br />

Время в элементе управления Substitution

<asp:Substitution  ID=”sbsTime” runat=”server” MethodName=”GetTime” />
</div>
</form>

Обратите внимание, что атрибут MethodName установлен на GetTime. На веб-странице отображаются два значения времени, оба из которых одинаковы. Если обратиться к той же странице спустя 25 секунд, то можно заметить, что значение времени, отображаемое на кэшированной странице, не обновляется, поскольку длительность кэширования страницы установлена на 60 секунд. Однако значение времени в элементе управления Substitution, sbsTime, обновляется для отображения системного времени по истечении 25 секунд. Это происходит потому, что элемент управления Substitution не был кэширован.

Послекэшевую подстановку также можно реализовать с помощью API подстановки. В API подстановки используется метод Response.WriteSubstitution() вместо элемента управления Substitution. В приведенном ниже коде использование API подстановки выделено жирным шрифтом.

<%@ Page Language=”C#” AutoEventWireup=”true” CodeFile=”Default.aspx.cs” Inherits=”Default” %>
<%@ OutputCache Duration=”60” VaryByParam=”None” %>
<form id=”form1” runat=”server”>
<div> Time in cached page:
<asp:Label ID=”lblTime”  runat=”server”></asp:Label>
<br />
<br />

Время в элементе управления Substitution

<% Response.WriteSubstitution(new HttpResponseSubstitutionCallback(GetTime)); %>
</div>
</form>

Метод Response.WriteSubstitution() можно использовать и в вынесенном (code-behind) коде веб-страницы. В результате вызова метода Response.WriteSubstitution() происходит переключение с кэширования на стороне клиента на кэширование на сервере. Это означает, что страница не будет кэшироваться на клиентском устройстве. Метод WriteSubstitution() принимает в качестве параметра экземпляр делегата HttpResponseSubstitutionCallback. Для замены динамического элемента или раздела на кэшированной странице этому делегату можно передать метод, элемент управления или объект. В приведенном выше коде имя статического метода GetTime() передается делегату, возвращающему в свою очередь динамическое содержимое, которое будет вставлено в страницу. В этом случае в виде строки будет возвращено текущее системное время.

При первом запросе страницы метод WriteSubstitution() вызывает делегат HttpResponseSubstitutionCallback для создания динамического содержимого. Затем в ответ добавляется подстановочный буфер. В этом буфере хранится делегат, который при последующих запросах может использоваться повторно. Затем механизм кэширования страницы изменяется с публичного на серверный. Это гарантирует вызов делегата при последующих обращениях к странице.

Настройка кэширования

Параметры кэширования при выводе страниц действительны только для конкретной веб-страницы. Однако иногда возникают ситуации, когда необходимо применить одни и те же настройки кэширования к нескольким страницам. Для указания такой конфигурационной информации в ASP.NET используется файл Web.config. Преимущество настройки кэширования с помощью конфигурационных файлов заключается в том, что все изменения, которые необходимо внести, производятся централизованно. К тому же настройки, указанные в конфигурационных файлах, могут применяться к нескольким страницам или всему веб-приложению. Файл Web.config содержит два элемента для настройки кэширования вывода страниц: <outputCacheSettings> и <outputCache>.

Элемент <outputCacheSettings>

Элемент <outputCacheSettings> позволяет хранить настройки кэширования для одной или нескольких страниц в веб-приложении. Это полезно, например когда необходимо кэшировать определенное количество страниц в течение 60 минут, а другой набор страниц — в течение 30 минут. Это достигается путем создания профилей кэширования в файле Web.config. Элемент <outputCacheProfile> позволяет определить один или несколько профилей кэширования. В приведенном ниже коде показано, как создаются профили кэширования.

<configuration>
  <system.web>
    <caching>
      <outputCacheSettings>
        <outputCacheProfiles>
          <add name=”Cache60Mins” duration=”3600” enabled=”true” />
          <add name=”Cache30Mins” duration=”1800” />
        </outputCacheProfiles>
      </outputCacheSettings>
    </caching>
  </system.web>
</configuration>

Обратите внимание, что элемент <outputCacheProfiles> вложен в элемент <outputCacheSettings>, который, в свою очередь, вложен в элемент <caching>. Профиль кэширования создается с помощью элемента <add>. Первый элемент <add> создает профиль кэширования с именем Cache60Mins для кэширования страниц в течение 60 минут. Второй элемент <add> создает профиль кэширования с именем Cache30Mins для кэширования страниц в течение 30 минут. Обратите внимание, что атрибут enabled элемента <add> является необязательным, а его значение true указывает на то, что кэширование вывода включено.

После определения профилей кэширования в файле Web.config на них можно ссылаться в коде веб-страниц с помощью директивы @outputCache. Ниже приведен код, позволяющий связать профиль кэширования с веб-страницей.

<%@ OuputCache CacheProfile=”Cache60Mins” VaryByParam=”None” %>

Директива @OutputCache использует имя профиля кэширования Cache60Mins для кэширования веб-страницы в течение 60 минут. Обратите внимание, что наряду с атрибутом CacheProfile должен обязательно использоваться атрибут VaryByParam или VaryByControl, как показано в коде выше. Все атрибуты, допустимые для использования с директивой @OutputCache, можно указывать в качестве атрибутов элемента <add> элемента <outputCacheProfiles>.

Элемент <outputCache>

Элемент <outputCache> используется для настройки кэширования вывода страниц веб-приложения. Этот элемент не требует создания дочернего элемента. Все настройки кэширования вывода страниц задаются с помощью атрибутов. К атрибутам элемента <outputCache> относятся:

enableOutputCache

Значение true включает кэширование вывода страниц для веб-приложения. Значением по умолчанию является true.

enableFragmentCache

Значение true включает фрагментарное кэширование веб-приложения. Значением по умолчанию является false.

sendCacheControlHeader

Если модулем кэширования вывода по умолчанию отправляется заголовок cache-control:private, этот атрибут возвращает значение Boolean. Значением по умолчанию является false.

omitVaryStar

Значение true включает отправку HTTP-заголовка «vary:*». Значением по умолчанию является false.

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

<caching>
    <outputCache enableOutputCache=”False” />
</caching>

Резюме

Кэширование сокращает время отклика веб-приложения за счет хранения данных в кэше. Кэширование данных приложения позволяет кэшировать наборы данных, объекты DataTable и пр. Метод Add() класса Cache используется для добавления элемента в кэш приложения. Кэширование вывода страниц позволяет кэшировать отдельные веб-страницы. Послекэшевая подстановка исключает фрагменты веб-страницы из кэширования. С помощью профилей кэширования можно задавать параметры кэширования для группы веб-страниц. Элементы <ouputCache> и <outputCacheSettings> в файлах Web.Config используются для настройки параметров кэширования вывода страниц.


Материал подготовлен в рамках курса «C# Developer. Professional». Если вам интересно узнать подробнее о формате обучения и программе, познакомиться с преподавателем курса — приглашаем на день открытых дверей онлайн. Регистрация здесь.