Повышение производительности благодаря кэшированию вывода (VB)
от Майкрософт
Из этого руководства вы узнаете, как значительно повысить производительность веб-приложений ASP.NET MVC, используя кэширование выходных данных. Вы узнаете, как кэшировать результат, возвращаемый действием контроллера, чтобы не нужно было создавать одно и то же содержимое каждый раз, когда новый пользователь вызывает действие.
Цель этого руководства — объяснить, как можно значительно повысить производительность приложения ASP.NET MVC, используя преимущества кэша вывода. Кэш вывода позволяет кэшировать содержимое, возвращаемое действием контроллера. Таким образом, при каждом вызове одного и того же действия контроллера не требуется создавать одно и то же содержимое.
Представьте, например, что приложение ASP.NET MVC отображает список записей базы данных в представлении Индекс. Как правило, каждый раз, когда пользователь вызывает действие контроллера, возвращающее представление индекса, набор записей базы данных должен быть извлечен из базы данных путем выполнения запроса к базе данных.
С другой стороны, если воспользоваться преимуществами кэша вывода, можно избежать выполнения запроса к базе данных каждый раз, когда пользователь вызывает одно и то же действие контроллера. Представление можно получить из кэша, а не повторно создать из действия контроллера. Кэширование позволяет избежать выполнения избыточной работы на сервере.
Включение кэширования выходных данных
Кэширование выходных данных включается путем добавления атрибута <OutputCache> к отдельному действию контроллера или ко всему классу контроллера. Например, контроллер в листинге 1 предоставляет действие с именем Index(). Выходные данные действия Index() кэшируются в течение 10 секунд.
Листинг 1. Controllers\HomeController.vb
<HandleError()> _
Public Class HomeController
Inherits System.Web.Mvc.Controller
<OutputCache(Duration:=10, VaryByParam:="none")> _
Function Index()
Return View()
End Function
End Class
В бета-версиях ASP.NET MVC кэширование выходных данных не работает для URL-адреса, например http://www.MySite.com/
. Вместо этого необходимо ввести URL-адрес, например .http://www.MySite.com/Home/Index
В листинге 1 выходные данные действия Index() кэшируются в течение 10 секунд. При желании можно указать гораздо больший срок кэширования. Например, если требуется кэшировать выходные данные действия контроллера в течение одного дня, можно указать длительность кэша 86400 секунд (60 секунд * 60 минут * 24 часа).
Нет никакой гарантии, что содержимое будет кэшироваться в течение указанного периода времени. При нехватке ресурсов памяти кэш начинает автоматически вытеснить содержимое.
Контроллер Home в листинге 1 возвращает представление индекса в листинге 2. В этом представлении нет ничего особенного. В представлении Индекс просто отображается текущее время (см. рис. 1).
Листинг 2. Views\Home\Index.aspx
<%@ Page Language="VB" Inherits="System.Web.Mvc.ViewPage" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
</head>
<body>
<div>
The current time is: <%= DateTime.Now.ToString("T") %>
</div>
</body>
</html>
Рис. 1. Представление кэшированного индекса
Если вы вызываете действие Index() несколько раз, введя URL-адрес /Home/Index в адресной строке браузера и повторно нажимая кнопку Обновить/перезагрузить в браузере, время, отображаемое в представлении индекса, не изменится в течение 10 секунд. То же время отображается, так как представление кэшируется.
Важно понимать, что одно и то же представление кэшируется для всех, кто посещает ваше приложение. Любой пользователь, вызывающий действие Index(), получит ту же кэшированную версию представления индекса. Это означает, что объем работы, который веб-сервер должен выполнить для обслуживания представления индекса, значительно сокращается.
Представление в листинге 2 делает что-то очень простое. В представлении просто отображается текущее время. Однако можно так же легко кэшировать представление, в котором отображается набор записей базы данных. В этом случае набор записей базы данных не требуется извлекать из базы данных каждый раз при вызове действия контроллера, возвращающего представление. Кэширование может сократить объем работы, который должен выполнять веб-сервер и сервер базы данных.
Не используйте директиву %@ OutputCache %> страницы <в представлении MVC. Эта директива истекла из веб-формы мира и не должна использоваться в приложении ASP.NET MVC.
Место кэширования содержимого
По умолчанию при использовании атрибута <OutputCache> содержимое кэшируется в трех расположениях: веб-сервер, все прокси-серверы и веб-браузер. Вы можете точно управлять местом кэширования содержимого, изменив свойство Location атрибута <OutputCache> .
Для свойства Location можно задать любое из следующих значений:
· Любой
· Клиента
· Вниз по течению
· Сервера
· Ни один
· ServerAndClient
По умолчанию свойство Location имеет значение Any. Однако существуют ситуации, в которых может потребоваться кэшировать только в браузере или только на сервере. Например, при кэшировании сведений, персонализированных для каждого пользователя, не следует кэшировать эти сведения на сервере. Если вы отображаете разные сведения для разных пользователей, следует кэшировать сведения только на клиенте.
Например, контроллер в листинге 3 предоставляет действие с именем GetName(), которое возвращает текущее имя пользователя. Если Джек входит на веб-сайт и вызывает действие GetName(), действие возвращает строку "Hi Jack". Если впоследствии Джилл войдет на веб-сайт и вызовет действие GetName(), она также получит строку "Hi Jack". Строка кэшируется на веб-сервере для всех пользователей после того, как Джек изначально вызывает действие контроллера.
Листинг 3. Controllers\BadUserController.vb
Public Class BadUserController
Inherits System.Web.Mvc.Controller
<OutputCache(Duration:=3600, VaryByParam:="none")> _
Function Index()
Return "Hi " & User.Identity.Name
End Function
End Class
Скорее всего, контроллер в листинге 3 работает неправильно. Вы не хотите отображать сообщение "Привет, Джек" для Джилл.
Никогда не следует кэшировать персонализированное содержимое в кэше сервера. Однако для повышения производительности может потребоваться кэшировать персонализированное содержимое в кэше браузера. Если вы кэшируете содержимое в браузере и пользователь вызывает одно и то же действие контроллера несколько раз, содержимое можно извлечь из кэша браузера, а не из сервера.
Измененный контроллер в листинге 4 кэширует выходные данные действия GetName(). Однако содержимое кэшируется только в браузере, а не на сервере. Таким образом, когда несколько пользователей вызывают метод GetName(), каждый пользователь получает собственное имя пользователя, а не имя другого пользователя.
Листинг 4. Controllers\UserController.vb
Public Class UserController
Inherits System.Web.Mvc.Controller
<OutputCache(Duration:=3600, VaryByParam:="none", Location:=OutputCacheLocation.Client, NoStore:=True)> _
Function GetName()
Return "Hi " & User.Identity.Name
End Function
End Class
Обратите внимание, что <атрибут OutputCache> в листинге 4 содержит свойство Location со значением OutputCacheLocation.Client. Атрибут <OutputCache> также содержит свойство NoStore. Свойство NoStore используется для информирования прокси-серверов и браузеров о том, что они не должны хранить постоянную копию кэшированного содержимого.
Изменение кэша вывода
В некоторых ситуациях могут потребоваться разные кэшированные версии одного и того же содержимого. Представьте, например, что вы создаете страницу master или сведений. На странице master отображается список названий фильмов. Щелкнув заголовок, вы получите сведения о выбранном фильме.
Если кэшировать страницу сведений, то сведения о том же фильме будут отображаться независимо от того, какой фильм вы щелкаете. Первый фильм, выбранный первым пользователем, будет отображаться для всех будущих пользователей.
Эту проблему можно устранить, воспользовавшись свойством VaryByParam атрибута <OutputCache> . Это свойство позволяет создавать разные кэшированные версии одного и того же содержимого, если параметр формы или параметр строки запроса отличается.
Например, контроллер в листинге 5 предоставляет два действия с именами Master() и Details(). Действие Master() возвращает список названий фильмов, а действие Details() — сведения о выбранном фильме.
Листинг 5. Controllers\MoviesController.vb
Public Class MoviesController
Inherits System.Web.Mvc.Controller
Private _dataContext As MovieDataContext
Public Sub New()
_dataContext = New MovieDataContext()
End Sub
<OutputCache(Duration:=Integer.MaxValue, VaryByParam:="none")> _
Public Function Master()
ViewData.Model = (From m In _dataContext.Movies _
Select m).ToList()
Return View()
End Function
<OutputCache(Duration:=Integer.MaxValue, VaryByParam:="id")> _
Public Function Details(ByVal id As Integer)
ViewData.Model = _dataContext.Movies.SingleOrDefault(Function(m) m.Id = id)
Return View()
End Function
End Class
Действие Master() содержит свойство VaryByParam со значением none. При вызове действия Master() возвращается та же кэшированная версия главного представления. Любые параметры формы или параметры строки запроса игнорируются (см. рис. 2).
Рис. 2. Представление /Movies/Master
Рис. 3. Представление /Movies/Details
Действие Details() содержит свойство VaryByParam со значением "Id". При передаче различных значений параметра Id в действие контроллера создаются разные кэшированные версии представления Сведений.
Важно понимать, что использование свойства VaryByParam приводит к большему и не меньшему кэшированию. Для каждой версии параметра Id создается другая кэшированная версия представления Сведений.
Для свойства VaryByParam можно задать следующие значения:
* = создавайте другую кэшированную версию при каждом изменении параметра формы или строки запроса.
none = никогда не создавайте разные кэшированные версии
Список параметров с запятой = создание различных кэшированных версий при каждом изменении параметров формы или строки запроса в списке
Создание профиля кэша
В качестве альтернативы настройке свойств кэша вывода путем изменения свойств атрибута <OutputCache> можно создать профиль кэша в файле веб-конфигурации (web.config). Создание профиля кэша в файле веб-конфигурации дает ряд важных преимуществ.
Во-первых, настроив кэширование выходных данных в файле веб-конфигурации, можно управлять тем, как действия контроллера кэшируют содержимое в одном центральном расположении. Вы можете создать один профиль кэша и применить его к нескольким контроллерам или действиям контроллера.
Во-вторых, вы можете изменить файл веб-конфигурации без повторной компиляции приложения. Если необходимо отключить кэширование для приложения, которое уже было развернуто в рабочей среде, можно просто изменить профили кэша, определенные в файле веб-конфигурации. Все изменения в файле веб-конфигурации будут обнаружены и применены автоматически.
Например, раздел <веб-конфигурации кэширования> в листинге 6 определяет профиль кэша с именем Cache1Hour. Раздел <кэширования> должен находиться в <разделе system.web> файла веб-конфигурации.
Листинг 6. Раздел кэширования для web.config
<caching>
<outputCacheSettings>
<outputCacheProfiles>
<add name="Cache1Hour" duration="3600" varyByParam="none"/>
</outputCacheProfiles>
</outputCacheSettings>
</caching>
Контроллер в листинге 7 показывает, как можно применить профиль Cache1Hour к действию контроллера с помощью атрибута <OutputCache> .
Листинг 7. Controllers\ProfileController.vb
Public Class ProfileController
Inherits System.Web.Mvc.Controller
<OutputCache(CacheProfile:="Cache1Hour")> _
Function Index()
Return DateTime.Now.ToString("T")
End Function
End Class
Если вы вызываете действие Index(), предоставляемое контроллером в листинге 7, то же время будет возвращено в течение 1 часа.
Итоги
Кэширование выходных данных обеспечивает очень простой способ существенного повышения производительности ASP.NET приложений MVC. В этом руководстве вы узнали, как использовать <атрибут OutputCache> для кэширования выходных данных действий контроллера. Вы также узнали, как изменить свойства атрибута <OutputCache> , такие как Duration и VaryByParam, чтобы изменить способ кэширования содержимого. Наконец, вы узнали, как определять профили кэша в файле веб-конфигурации.