Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В любом веб-приложении некоторые данные часто используются, а некоторые данные редко используются. Мы можем повысить производительность приложения ASP.NET, загрузив заранее часто используемые данные, метод, известный как кэширование. В этом руководстве демонстрируется один из подходов к упреждающей загрузке, которая заключается в загрузке данных в кэш при запуске приложения.
Введение
Два предыдущих руководства рассмотрели кэширование данных в слоях презентации и кэширования. В кэшировании данных с помощью ObjectDataSource мы рассмотрели использование функций кэширования ObjectDataSource для кэширования данных на уровне презентации. Кэширование данных в архитектуре было рассмотрено в новом, отдельном слое кэширования. Оба этих учебника использовали реактивную загрузку при работе с кэшем данных. При реактивной загрузке при каждом запросе данных система сначала проверяет, находится ли она в кэше. Если нет, он захватывает данные из исходного источника, например базы данных, а затем сохраняет его в кэше. Основным преимуществом реактивной загрузки является его простота реализации. Одним из его недостатков является неравномерность производительности в разных запросах. Представьте себе страницу, которая использует слой кэширования из предыдущего руководства для отображения сведений о продукте. Когда эта страница посещается в первый раз или посещается в первый раз после вытеснения кэшированных данных из-за ограничений памяти или указанного истечения срока действия, данные должны быть извлечены из базы данных. Таким образом, эти запросы пользователей будут занимать больше времени, чем запросы пользователей, которые могут обслуживаться кэшем.
Упреждающая загрузка предоставляет альтернативную стратегию управления кэшем, которая сглаживает производительность запросов, загружая кэшированные данные до необходимости. Как правило, упреждающая загрузка использует некоторый процесс, который периодически проверяет или уведомляется при обновлении базовых данных. Затем этот процесс обновляет кэш, чтобы сохранить его свежим. Упреждающая загрузка особенно полезна, если базовые данные исходят из медленного подключения к базе данных, веб-службы или другого особенно вялого источника данных. Но этот подход к упреждающей загрузке сложнее реализовать, так как он требует создания, управления и развертывания процесса для проверки изменений и обновления кэша.
Другой вариант упреждающей загрузки, и тип, который мы рассмотрим в этом руководстве, — загрузка данных в кэш при запуске приложения. Этот подход особенно полезен для кэширования статических данных, таких как записи в таблицах сопоставления баз данных.
Замечание
Дополнительные сведения о различиях между упреждающей и реактивной загрузкой, а также списками плюсов, минусов и рекомендаций по реализации см. в разделе "Управление содержимым кэша " руководства по архитектуре кэширования для приложений .NET Framework.
Шаг 1. Определение данных для кэширования при запуске приложения
Примеры кэширования с использованием реактивной загрузки, которые мы изучили в предыдущих двух руководствах, хорошо работают с данными, которые могут периодически изменяться и не занимает непомерно долгое время для создания. Но если кэшированные данные никогда не изменяются, срок действия, используемый реактивной загрузкой, является лишним. Аналогичным образом, если данные, которые кэшируются, требуют чрезвычайно много времени для генерации, то пользователи, чьи запросы ищут пустой кэш, будут вынуждены долго ждать, пока извлекаются базовые данные. Рассмотрите возможность кэширования статических данных и данных, которые требуют исключительно длительного времени для создания при запуске приложения.
Хотя базы данных имеют множество динамических часто изменяющихся значений, большинство из них также имеют справедливый объем статических данных. Например, практически все модели данных имеют один или несколько столбцов, содержащих определенное значение из фиксированного набора вариантов. Таблица Patients
базы данных может иметь PrimaryLanguage
столбец, набор значений которого может быть английский, испанский, французский, русский, японский и т. д. Часто эти типы столбцов реализуются с помощью таблиц подстановки. Вместо хранения строки на английском или французском языках в Patients
таблице создается вторая таблица, которая имеет, как правило, два столбца — уникальный идентификатор и строковое описание — с записью для каждого возможного значения. Столбец PrimaryLanguage
в таблице Patients
хранит соответствующий уникальный идентификатор в таблице поиска. На рисунке 1 указано, что родной язык Джона Доу — английский, а Эда Джонсона — русский.
Рис. 1. Таблица Languages
— это таблица подстановки, используемая таблицей Patients
.
Пользовательский интерфейс для редактирования или создания нового пациента будет включать раскрывающийся список допустимых языков, заполненных записями в Languages
таблице. Без кэширования при каждом посещении этого интерфейса система должна запрашивать таблицу Languages
. Это расточительно и ненужно, так как значения таблицы поиска изменяются очень редко, если вообще когда-либо.
Мы могли кэшировать Languages
данные, используя те же методы реактивной загрузки, которые рассматриваются в предыдущих руководствах. Однако реактивная загрузка использует срок действия на основе времени, который не требуется для статических данных таблицы подстановки. Хотя кэширование с помощью реактивной загрузки было бы лучше, чем отсутствие кэширования, наиболее оптимальным подходом было бы заранее загрузить данные таблицы подстановки в кэш при запуске приложения.
В этом руководстве мы рассмотрим, как кэшировать данные таблицы подстановки и другие статические сведения.
Шаг 2. Изучение различных способов кэширования данных
Сведения можно программно кэшировать в приложении ASP.NET с помощью различных подходов. Мы уже видели, как использовать кэш данных в предыдущих руководствах. Кроме того, объекты можно программно кэшировать с помощью статических элементов или состояния приложения.
При работе с классом как правило, сначала должен быть создан его экземпляр, прежде чем можно будет получить доступ к его элементам. Например, чтобы вызвать метод из одного из классов на уровне бизнес-логики, сначала необходимо создать экземпляр класса:
ProductsBLL productsAPI = new ProductsBLL();
productsAPI.SomeMethod();
productsAPI.SomeProperty = "Hello, World!";
Прежде чем вызывать SomeMethod или работать с SomeProperty, необходимо сначала создать экземпляр класса с помощью new
ключевого слова.
SomeMethod и SomeProperty являются частью конкретного экземпляра. Время существования этих элементов связано со временем существования связанного объекта.
Статические члены, с другой стороны, являются переменными, свойствами и методами, общими для всех экземпляров класса и, следовательно, имеют время существования до тех пор, пока класс. Статические члены указываются ключевым словом static
.
Помимо статических элементов, данные можно кэшировать с помощью состояния приложения. Каждое приложение ASP.NET поддерживает коллекцию имен и значений, доступную всем пользователям и страницам приложения. Доступ к этой коллекции можно получить с помощью свойства HttpContext
класса и использовать в коде класса ASP.NET страницы следующим образом:
Application["key"] = value;
object value = Application["key"];
Кэш данных предоставляет гораздо более широкий API для кэширования данных, предоставляя механизмы истечения срока действия и зависимостей, приоритеты элементов кэша и т. д. С статическими элементами и состоянием приложения такие функции необходимо добавить вручную разработчиком страницы. Однако при кэшировании данных при запуске приложения в течение всего времени существования приложения преимущества кэша данных являются спорными. В этом руководстве мы рассмотрим код, который использует все три метода кэширования статических данных.
Шаг 3. КэшированиеSuppliers
данных таблицы
Таблицы базы данных Northwind, реализованные на сегодняшний день, не включают в себя традиционные таблицы подстановки. Четыре DataTable, реализованные в нашей DAL, моделируют таблицы, значения которых являются нестатичными. Вместо того чтобы тратить время на добавление нового DataTable в DAL, а затем нового класса и методов в BLL, для этого руководства давайте просто представим, что данные таблицы Suppliers
являются статическими. Поэтому мы можем кэшировать эти данные при запуске приложения.
Чтобы начать, создайте новый класс с именем StaticCache.cs
в папке CL
.
Рис. 2. Создание StaticCache.cs
класса в папке CL
Необходимо добавить метод, который загружает данные при запуске в соответствующее хранилище кэша, а также методы, возвращающие данные из этого кэша.
[System.ComponentModel.DataObject]
public class StaticCache
{
private static Northwind.SuppliersDataTable suppliers = null;
public static void LoadStaticCache()
{
// Get suppliers - cache using a static member variable
SuppliersBLL suppliersBLL = new SuppliersBLL();
suppliers = suppliersBLL.GetSuppliers();
}
[DataObjectMethodAttribute(DataObjectMethodType.Select, true)]
public static Northwind.SuppliersDataTable GetSuppliers()
{
return suppliers;
}
}
Приведенный выше код использует статическую переменную suppliers
для сохранения результатов метода SuppliersBLL
класса GetSuppliers()
, который вызывается из метода LoadStaticCache()
. Метод LoadStaticCache()
должен вызываться во время запуска приложения. После загрузки этих данных при запуске приложения любая страница, которая должна работать с данными поставщика, может вызвать StaticCache
метод класса GetSuppliers()
. Таким образом, вызов базы данных для получения поставщиков происходит только один раз при запуске приложения.
Вместо того, чтобы использовать статическую переменную-член в качестве хранилища кэша, можно было бы также использовать состояние приложения или кэш данных. В следующем коде показано, как класс переработан для использования состояния приложения.
[System.ComponentModel.DataObject]
public class StaticCache
{
public static void LoadStaticCache()
{
// Get suppliers - cache using application state
SuppliersBLL suppliersBLL = new SuppliersBLL();
HttpContext.Current.Application["key"] = suppliersBLL.GetSuppliers();
}
[DataObjectMethodAttribute(DataObjectMethodType.Select, true)]
public static Northwind.SuppliersDataTable GetSuppliers()
{
return HttpContext.Current.Application["key"] as Northwind.SuppliersDataTable;
}
}
В LoadStaticCache()
этом случае сведения о поставщике хранятся в ключе переменной приложения. Он возвращается в качестве соответствующего типа (Northwind.SuppliersDataTable
) из GetSuppliers()
. Хотя состояние приложения можно получить в классах кода ASP.NET страниц с помощью Application["key"]
, в рамках архитектуры необходимо использовать HttpContext.Current.Application["key"]
, чтобы получить текущее HttpContext
.
Аналогичным образом кэш данных можно использовать в качестве хранилища кэша, как показано в следующем коде:
[System.ComponentModel.DataObject]
public class StaticCache
{
public static void LoadStaticCache()
{
// Get suppliers - cache using the data cache
SuppliersBLL suppliersBLL = new SuppliersBLL();
HttpRuntime.Cache.Insert(
/* key */ "key",
/* value */ suppliers,
/* dependencies */ null,
/* absoluteExpiration */ Cache.NoAbsoluteExpiration,
/* slidingExpiration */ Cache.NoSlidingExpiration,
/* priority */ CacheItemPriority.NotRemovable,
/* onRemoveCallback */ null);
}
[DataObjectMethodAttribute(DataObjectMethodType.Select, true)]
public static Northwind.SuppliersDataTable GetSuppliers()
{
return HttpRuntime.Cache["key"] as Northwind.SuppliersDataTable;
}
}
Чтобы добавить элемент в кэш данных без истечения срока действия, используйте значения System.Web.Caching.Cache.NoAbsoluteExpiration
и System.Web.Caching.Cache.NoSlidingExpiration
в качестве входных параметров. Эта конкретная перегрузка метода кэша Insert
данных была выбрана, чтобы указать приоритет элемента кэша. Приоритет используется для определения элементов, которые следует удалять из кэша при низком уровне доступной памяти. Здесь мы используем приоритет NotRemovable
, который гарантирует, что этот элемент кэша не будет разобран.
Замечание
Файл для загрузки этого руководства реализует класс StaticCache
с использованием метода статической переменной. Код для методов кэширования данных и состояния приложения доступен в комментариях в файле класса.
Шаг 4. Выполнение кода при запуске приложения
Чтобы выполнить код при первом запуске веб-приложения, необходимо создать специальный файл с именем Global.asax
. Этот файл может содержать обработчики событий для событий уровня приложения, сеанса и запроса и здесь можно добавить код, который будет выполняться при запуске приложения.
Global.asax
Добавьте файл в корневой каталог веб-приложения, щелкнув правой кнопкой мыши имя проекта веб-сайта в обозревателе решений Visual Studio и выбрав "Добавить новый элемент". В диалоговом окне "Добавить новый элемент" выберите тип элемента "Глобальный класс приложения" и нажмите кнопку "Добавить".
Замечание
Если у вас уже есть файл в проекте, тип элемента "Глобальный Global.asax
класс приложения" не будет указан в диалоговом окне "Добавление нового элемента".
Рис. 3. Добавление файла в Global.asax
корневой каталог веб-приложения (щелкните, чтобы просмотреть изображение полного размера)
Шаблон файла по умолчанию Global.asax
включает пять методов в теге на стороне <script>
сервера:
-
Application_Start
выполняется при первом запуске веб-приложения -
Application_End
выполняется при завершении работы приложения -
Application_Error
выполняется всякий раз, когда необработанное исключение достигает приложения -
Session_Start
выполняется при создании нового сеанса -
Session_End
выполняется при истечении срока действия сеанса или отмене
Обработчик Application_Start
событий вызывается только один раз во время жизненного цикла приложения. Приложение запускается при первом запросе ресурса ASP.NET из приложения и продолжает выполняться до перезапуска приложения, который может произойти из-за изменения содержимого папки /Bin
, изменения Global.asax
, изменения содержимого в папке App_Code
или изменения файла Web.config
, среди других причин. Дополнительные сведения о жизненном цикле приложения см. в ASP.NET обзоре жизненного цикла приложения.
Для этих учебных пособий нам нужно добавить код только в метод Application_Start
, поэтому вы можете удалить остальные. Просто вызовите метод Application_Start
класса StaticCache
, который загрузит и кэширует сведения о поставщике:
<%@ Application Language="C#" %>
<script runat="server">
void Application_Start(object sender, EventArgs e)
{
StaticCache.LoadStaticCache();
}
</script>
Вот и всё! При запуске приложения метод LoadStaticCache()
будет извлекать сведения о поставщике из BLL и сохранять их в статической переменной (или любом хранилище кэша, которое вы использовали в конце концов в классе StaticCache
). Чтобы проверить это поведение, установите точку останова в методе Application_Start
и запустите приложение. Обратите внимание, что точка останова достигается при запуске приложения. Однако последующие запросы не приводят к выполнению метода Application_Start
.
Рис. 4. Использование точки останова для проверки выполнения Application_Start
обработчика событий (щелкните, чтобы просмотреть изображение полного размера)
Замечание
Если при первом запуске отладки вы не попали в точку Application_Start
останова, это связано с тем, что приложение уже запущено. Принудительно перезапустите приложение, изменив файлы Global.asax
или Web.config
, и затем попробуйте снова. Вы можете просто добавить (или удалить) пустую строку в конце одного из этих файлов, чтобы быстро перезапустить приложение.
Шаг 5. Отображение кэшированных данных
На этом этапе StaticCache
класс имеет версию данных поставщика, кэшированных при запуске приложения, к которым можно получить доступ через его GetSuppliers()
метод. Для работы с данными на уровне представления можно использовать ObjectDataSource или программно вызвать метод StaticCache
класса GetSuppliers()
из класса кода ASP.NET страницы. Давайте рассмотрим использование элементов управления ObjectDataSource и GridView для отображения кэшированных сведений о поставщике.
Начните с открытия AtApplicationStartup.aspx
страницы в папке Caching
. Перетащите GridView из панели элементов в конструктор, присвойв свойству значение ID
Suppliers
. Затем из смарт-тега GridView выберите создать объект ObjectDataSource с именем SuppliersCachedDataSource
. Настройте ObjectDataSource для использования метода класса StaticCache
GetSuppliers()
.
Рис. 5. Настройка ObjectDataSource для использования StaticCache
класса (щелкните, чтобы просмотреть изображение полного размера)
Рис. 6. Использование GetSuppliers()
метода для получения кэшированных данных поставщика (щелкните, чтобы просмотреть изображение полного размера)
После завершения работы мастера Visual Studio автоматически добавит BoundFields для каждого из полей данных в SuppliersDataTable
. Декларативный код для ваших GridView и ObjectDataSource должна выглядеть следующим образом:
<asp:GridView ID="Suppliers" runat="server" AutoGenerateColumns="False"
DataKeyNames="SupplierID" DataSourceID="SuppliersCachedDataSource"
EnableViewState="False">
<Columns>
<asp:BoundField DataField="SupplierID" HeaderText="SupplierID"
InsertVisible="False" ReadOnly="True"
SortExpression="SupplierID" />
<asp:BoundField DataField="CompanyName" HeaderText="CompanyName"
SortExpression="CompanyName" />
<asp:BoundField DataField="Address" HeaderText="Address"
SortExpression="Address" />
<asp:BoundField DataField="City" HeaderText="City"
SortExpression="City" />
<asp:BoundField DataField="Country" HeaderText="Country"
SortExpression="Country" />
<asp:BoundField DataField="Phone" HeaderText="Phone"
SortExpression="Phone" />
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="SuppliersCachedDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetSuppliers" TypeName="StaticCache" />
На рисунке 7 показана страница при просмотре через браузер. Выходные данные те же, как если бы мы извлекли их из класса BLL SuppliersBLL
, но использование класса StaticCache
возвращает данные поставщика, которые были кэшированы при запуске приложения. Точки останова StaticCache
можно задать в методе GetSuppliers()
класса, чтобы проверить это поведение.
Рис. 7. Кэшированные данные поставщика отображаются в GridView (щелкните, чтобы просмотреть изображение полного размера)
Сводка
Большинство моделей данных содержат значительное количество статических данных, обычно реализованных в виде таблиц поиска. Так как эта информация является статической, нет причин постоянного доступа к базе данных при каждом отображении этой информации. Кроме того, из-за статического характера при кэшировании данных не требуется устанавливать срок действия. В этом руководстве мы узнали, как принимать такие данные и кэшировать их в кэше данных, состоянии приложения и через статическую переменную-член. Эти сведения кэшируются при запуске приложения и остаются в кэше на протяжении всего времени существования приложения.
В этом учебном пособии и двух предыдущих мы изучили кэширование данных на протяжении всего времени существования приложения, наряду с использованием временных сроков действия. Однако при кэшировании данных базы данных срок действия на основе времени может быть меньше идеала. Вместо периодического очистки кэша было бы оптимальным только вытеснение кэшированного элемента при изменении базовых данных базы данных. Это идеальное решение можно использовать с помощью зависимостей кэша SQL, которые мы рассмотрим в следующем руководстве.
Счастливое программирование!
Сведения о авторе
Скотт Митчелл, автор семи книг ASP/ASP.NET и основатель 4GuysFromRolla.com, работает с технологиями Microsoft Web с 1998 года. Скотт работает независимым консультантом, тренером и писателем. Его последняя книга — Sams Teach Yourself ASP.NET 2.0 за 24 часа. С ним можно связаться по адресу mitchell@4GuysFromRolla.com.
Особое спасибо кому
Эта серия учебников была проверена многими полезными рецензентами. Ведущими рецензентами этого руководства были Тереза Мерфи и Зак Джонс. Хотите просмотреть мои предстоящие статьи MSDN? Если да, напишите мне на mitchell@4GuysFromRolla.com.