Кэширование данных при запуске приложения (VB)

Скотт Митчелл

Загрузить PDF-файл

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

Введение

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

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

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

Примечание

Дополнительные сведения о различиях между упреждающей и реактивной загрузкой, а также списки плюсов, недостатков и рекомендаций по реализации см. в разделе Управление содержимым кэшаруководства по архитектуре кэширования для приложений платформа .NET Framework.

Шаг 1. Определение данных для кэширования при запуске приложения

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

Хотя базы данных имеют много динамических часто изменяющихся значений, большинство из них также имеют достаточное количество статических данных. Например, практически все модели данных имеют один или несколько столбцов, содержащих определенное значение из фиксированного набора вариантов. Таблица Patients базы данных может содержать столбец PrimaryLanguage , набор значений которого может быть английский, испанский, французский, русский, японский и т. д. Часто эти типы столбцов реализуются с помощью таблиц подстановки. Вместо хранения строки на английском или французском языках в Patients таблице создается вторая таблица, которая обычно содержит два столбца — уникальный идентификатор и описание строки — с записью для каждого возможного значения. В PrimaryLanguage столбце Patients таблицы хранится соответствующий уникальный идентификатор в таблице подстановки. На рис. 1 основной язык пациента Джона Доу — английский, а Эд Джонсон — русский.

Таблица Languages — это таблица подстановки, используемая таблицей пациентов

Рис. 1. Таблица Languages представляет собой таблицу подстановки, используемую таблицей Patients

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

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

В этом руководстве мы рассмотрим, как кэшировать данные таблицы подстановки и другие статические сведения.

Шаг 2. Изучение различных способов кэширования данных

Сведения можно кэшировать программными средствами в приложении ASP.NET с помощью различных подходов. Мы уже видели, как использовать кэш данных в предыдущих руководствах. Кроме того, объекты можно кэшировать программными средствами с помощью статических элементов или состояния приложения.

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

Dim productsAPI As New ProductsBLL()
productsAPI.SomeMethod()
productsAPI.SomeProperty = "Hello, World!"

Прежде чем вызывать SomeMethod или работать с SomeProperty, необходимо сначала создать экземпляр класса с помощью New ключевое слово. SomeMethod и SomeProperty связаны с определенным экземпляром. Время существования этих элементов привязано к времени существования связанного с ними объекта. Статические члены, с другой стороны, являются переменными, свойствами и методами, которые являются общими для всех экземпляров класса и, следовательно, имеют время существования, дольше, чем класс. Статические члены обозначаются ключевое слово Shared.

Помимо статических элементов, данные можно кэшировать с помощью состояния приложения. Каждое приложение ASP.NET поддерживает коллекцию имен и значений, доступную всем пользователям и страницам приложения. Доступ к этой коллекции можно получить с помощью HttpContext свойства класса Applicationи использовать из класса кода программной части ASP.NET страницы следующим образом:

Application("key") = value
Dim value As Object = Application("key")

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

Шаг 3. КэшированиеSuppliersданных таблицы

Таблицы базы данных Northwind, реализованные на сегодняшний день, не содержат традиционных таблиц подстановки. Четыре таблицы DataTable, реализованные в DAL, все таблицы моделей, значения которых не являются статическими. Вместо того, чтобы тратить время на добавление новой таблицы DataTable в DAL, а затем нового класса и методов в BLL, в этом руководстве просто притворяемся, что Suppliers данные таблицы являются статическими. Поэтому эти данные можно кэшировать при запуске приложения.

Для начала создайте класс с именем StaticCache.cs в папке CL .

Создание класса StaticCache.vb в папке CL

Рис. 2. Создание StaticCache.vb класса в папке CL

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

<System.ComponentModel.DataObject()> _
Public Class StaticCache
    Private Shared suppliers As Northwind.SuppliersDataTable = Nothing
    Public Shared Sub LoadStaticCache()
        ' Get suppliers - cache using a static member variable
        Dim suppliersBLL As New SuppliersBLL()
        suppliers = suppliersBLL.GetSuppliers()
    End Sub
    
    <DataObjectMethodAttribute(DataObjectMethodType.Select, True)> _
    Public Shared Function GetSuppliers() As Northwind.SuppliersDataTable
        Return suppliers
    End Function
End Class

Приведенный выше код использует статическую переменную-член suppliers, для хранения результатов из SuppliersBLL метода класса s GetSuppliers() , который вызывается из LoadStaticCache() метода . Метод LoadStaticCache() предназначен для вызова во время запуска приложения. После загрузки этих данных при запуске приложения любая страница, которая должна работать с данными StaticCache поставщика, может вызвать метод класса s GetSuppliers() . Таким образом, вызов базы данных для получения поставщиков выполняется только один раз при запуске приложения.

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

<System.ComponentModel.DataObject()> _
Public Class StaticCache
    Public Shared Sub LoadStaticCache()
        ' Get suppliers - cache using application state
        Dim suppliersBLL As New SuppliersBLL()
        HttpContext.Current.Application("key") = suppliers
    End Sub
    
    <DataObjectMethodAttribute(DataObjectMethodType.Select, True)> _
    Public Shared Function GetSuppliers() As Northwind.SuppliersDataTable
        Return TryCast(HttpContext.Current.Application("key"), _
            Northwind.SuppliersDataTable)
    End Function
End Class

В LoadStaticCache()сведения о поставщике хранятся в ключе переменной приложения. Он возвращается в качестве соответствующего типа (Northwind.SuppliersDataTable) из GetSuppliers(). Хотя доступ к состоянию приложения можно получить в классах кода программной части ASP.NET страниц с помощью Application("key"), в архитектуре необходимо использовать HttpContext.Current.Application("key") для получения текущего HttpContext.

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

<System.ComponentModel.DataObject()> _
Public Class StaticCache
    Public Shared Sub LoadStaticCache()
        ' Get suppliers - cache using a static member variable
        Dim suppliersBLL As New SuppliersBLL()
        HttpRuntime.Cache.Insert("key", suppliers, Nothing, _
            Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, _
            CacheItemPriority.NotRemovable, Nothing)
    End Sub
    <System.ComponentModel.DataObjectMethodAttribute_
    (System.ComponentModel.DataObjectMethodType.Select, True)> _
    Public Shared Function GetSuppliers() As Northwind.SuppliersDataTable
        Return TryCast(HttpRuntime.Cache("key"), Northwind.SuppliersDataTable)
    End Function
End Class

Чтобы добавить элемент в кэш данных без истечения срока действия на основе времени, используйте значения и в System.Web.Caching.Cache.NoAbsoluteExpirationSystem.Web.Caching.Cache.NoSlidingExpiration качестве входных параметров. Эта конкретная перегрузка метода кэша данных была выбрана Insert , чтобы можно было указать приоритет элемента кэша. Приоритет используется для определения элементов, которые следует удалить из кэша при нехватке доступной памяти. Здесь мы используем приоритет NotRemovable, который гарантирует, что этот элемент кэша не будет очищаться.

Примечание

В этом руководстве реализован StaticCache класс с использованием подхода статических переменных-членов. Код для методов кэширования состояния приложения и данных доступен в комментариях в файле класса.

Шаг 4. Выполнение кода при запуске приложения

Чтобы выполнить код при первом запуске веб-приложения, необходимо создать специальный файл с именем Global.asax. Этот файл может содержать обработчики событий уровня приложения, сеанса и запроса. Именно здесь можно добавить код, который будет выполняться при запуске приложения.

Добавьте файл в Global.asax корневой каталог веб-приложения, щелкнув правой кнопкой мыши имя проекта веб-сайта в Обозреватель решений Visual Studio и выбрав Добавить новый элемент. В диалоговом окне Добавление нового элемента выберите тип элемента Класс глобального приложения и нажмите кнопку Добавить.

Примечание

Если в проекте уже есть Global.asax файл, тип элемента Global Application Class не будет указан в диалоговом окне Добавление нового элемента.

Добавление файла 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 метод класса , LoadStaticCache() который будет загружать и кэшировать сведения о поставщике:

<%@ Application Language="VB" %>
<script runat="server">
    Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
        StaticCache.LoadStaticCache()
    End Sub
</script>

Это все, что есть к нему! При запуске LoadStaticCache() приложения метод заберет сведения о поставщике из BLL и сохранит их в переменной статического члена (или в любом кэше, которое вы использовали в StaticCache классе ). Чтобы проверить это поведение, установите точку останова в методе Application_Start и запустите приложение. Обратите внимание, что точка останова достигается при запуске приложения. Однако последующие запросы не приводят к выполнению 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()

Настройка ObjectDataSource для использования класса StaticCache

Рис. 5. Настройка ObjectDataSource для использования StaticCache класса (щелкните для просмотра полноразмерного изображения)

Получение кэшированных данных поставщика с помощью метода GetSuppliers()

Рис. 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 класса возвращает данные поставщика в кэше при запуске приложения. Для проверки этого поведения можно задать точки останова в методе StaticCacheGetSuppliers() класса .

Кэшированные данные поставщика отображаются в GridView

Рис. 7. Кэшированные данные поставщика отображаются в GridView (щелкните, чтобы просмотреть полноразмерное изображение)

Сводка

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

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

Счастливое программирование!

Об авторе

Скотт Митчелл (Scott Mitchell), автор семи книг ASP/ASP.NET и основатель 4GuysFromRolla.com, работает с Веб-технологиями Майкрософт с 1998 года. Скотт работает независимым консультантом, тренером и писателем. Его последняя книга Sams Teach Yourself ASP.NET 2.0 в 24 часа. Его можно связать по адресу mitchell@4GuysFromRolla.com. или через его блог, который можно найти по адресу http://ScottOnWriting.NET.

Отдельная благодарность

Эта серия учебников была проверена многими полезными рецензентами. В качестве ведущих рецензентов в этом руководстве были Тереса Мерфи и Зак Джонс. Хотите ознакомиться с моими предстоящими статьями MSDN? Если да, опустите мне строку в mitchell@4GuysFromRolla.com.