Кэширование данных и страниц в ASP.NET
Кэширование — это механизм, используемый веб-приложениями для повышения производительности. Сегодня веб-приложения разрабатываются в промышленных масштабах. Такие приложения используют кэширование, чтобы свести время отклика к минимуму.
Ниже перечислены некоторые проблемы веб-приложений и то, как они решаются с помощью кэширования.
Производительность
Веб-приложения хранят статические данные, такие как названия стран, списки годов и месяцев. Как правило, при каждом запросе страницы эти данные извлекаются из базы данных и отображаются на странице. Поэтому каждый посетитель такой страницы вынужден ожидать ее загрузки несколько секунд.
Кэширование позволяет хранить статические данные в хранилище, расположенном в непосредственной близости от потребителя этих данных. Например, статические данные можно хранить на стороне клиента, запрашивающего страницу, на сервере, предоставляющем страницу, либо на прокси-сервере. Прокси-сервером в данном случае выступает дополнительное устройство, поддерживающее кэширование 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». Если вам интересно узнать подробнее о формате обучения и программе, познакомиться с преподавателем курса — приглашаем на день открытых дверей онлайн. Регистрация здесь.