Добавление динамического содержимого на кэшированные страницы (C#)

от Корпорации Майкрософт

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

Используя кэширование выходных данных, вы можете значительно повысить производительность приложения ASP.NET MVC. Вместо повторного создания страницы при каждом запросе страницы ее можно создать один раз и кэшировать в памяти для нескольких пользователей.

Но есть проблема. Что делать, если вам нужно отобразить динамическое содержимое на странице? Например, представьте, что вы хотите отобразить объявление баннера на странице. Вы не хотите, чтобы объявление баннера кэшировались, чтобы каждый пользователь видел одно и то же объявление. Ты бы не зарабатывал деньги таким образом!

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

Обычно при выводе кэша страницы с помощью атрибута [OutputCache] страница кэшируется как на сервере, так и в клиенте (веб-браузере). При использовании подстановки после кэширования страница кэшируется только на сервере.

Использование подстановки после кэширования

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

Представьте, например, что вы хотите случайным образом отображать различные новости на кэшированных страницах. Класс в листинге 1 предоставляет один метод с именем RenderNews(), который случайным образом возвращает один элемент новостей из списка из трех элементов новостей.

Листинг 1 — Models\News.cs

using System;
using System.Collections.Generic;
using System.Web;

namespace MvcApplication1.Models
{
    public class News
    {
        public static string RenderNews(HttpContext context)
        {
            var news = new List<string> 
                { 
                    "Gas prices go up!", 
                    "Life discovered on Mars!", 
                    "Moon disappears!" 
                };
            
            var rnd = new Random();
            return news[rnd.Next(news.Count)];
        }
    }
}

Чтобы воспользоваться преимуществами подстановки после кэширования, вызовите метод HttpResponse.WriteSubstitution(). Метод WriteSubstitution() настраивает код для замены области кэшированных страниц динамическим содержимым. Метод WriteSubstitution() используется для отображения случайного элемента новостей в представлении в листинге 2.

Листинг 2. Views\Home\Index.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="MvcApplication1.Views.Home.Index" %>
<%@ Import Namespace="MvcApplication1.Models" %>
<!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>Index</title>
</head>
<body>
    <div>

    <% Response.WriteSubstitution(News.RenderNews); %>
        
    <hr />
    
    The content of this page is output cached.
    <%= DateTime.Now %>

    </div>
</body>
</html>

Метод RenderNews передается методу WriteSubstitution(). Обратите внимание, что метод RenderNews не вызывается (круглые скобки отсутствуют). Вместо этого ссылка на метод передается в WriteSubstitution().

Представление индексов кэшируется. Представление возвращается контроллером в листинге 3. Обратите внимание, что действие Index() имеет атрибут [OutputCache], который приводит к кэшированию представления индекса в течение 60 секунд.

Листинг 3. Controllers\HomeController.cs

using System.Web.Mvc;

namespace MvcApplication1.Controllers
{
    [HandleError]
    public class HomeController : Controller
    {
        [OutputCache(Duration=60, VaryByParam="none")]
        public ActionResult Index()
        {
            return View();
        }
    }
}

Несмотря на то, что представление индексов кэшировано, при запросе страницы индекса отображаются различные случайные элементы новостей. При запросе страницы Индекс время, отображаемое страницей, не изменяется в течение 60 секунд (см. рис. 1). Тот факт, что время не меняется, подтверждает, что страница кэширована. Однако содержимое, внедренное методом WriteSubstitution() — случайным элементом новостей, изменяется с каждым запросом .

Рис. 1. Внедрение динамических новостей в кэшированную страницу

clip_image002

Использование подстановки после кэширования во вспомогательных методах

Более простой способ воспользоваться преимуществами подстановки после кэширования — инкапсулировать вызов метода WriteSubstitution() в пользовательском вспомогательном методе. Этот подход показан вспомогательным методом в листинге 4.

Листинг 4— AdHelper.cs

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;

namespace MvcApplication1.Helpers
{
    public static class AdHelper
    {
        public static void RenderBanner(this HtmlHelper helper)
        {
            var context = helper.ViewContext.HttpContext;
            context.Response.WriteSubstitution(RenderBannerInternal);
        }
        
        private static string RenderBannerInternal(HttpContext context)
        {
            var ads = new List<string> 
                { 
                    "/ads/banner1.gif", 
                    "/ads/banner2.gif", 
                    "/ads/banner3.gif" 
                };

            var rnd = new Random();
            var ad = ads[rnd.Next(ads.Count)];
            return String.Format("<img src='{0}' />", ad);
        }
    }
}

В листинге 4 содержится статический класс, предоставляющий два метода: RenderBanner() и RenderBannerInternal(). Метод RenderBanner() представляет фактический вспомогательный метод. Этот метод расширяет стандартный ASP.NET класс HtmlHelper MVC, чтобы можно было вызывать Html.RenderBanner() в представлении так же, как и любой другой вспомогательный метод.

Метод RenderBanner() вызывает метод HttpResponse.WriteSubstitution(), передавая метод RenderBannerInternal() методу WriteSubstitution().

Метод RenderBannerInternal() является частным. Этот метод не будет предоставляться в качестве вспомогательного метода. Метод RenderBannerInternal() случайным образом возвращает одно рекламное изображение баннера из списка из трех рекламных баннеров.

В измененном представлении индексов в листинге 5 показано, как можно использовать вспомогательный метод RenderBanner(). Обратите внимание, что в верхней части представления включена дополнительная <директива %@ Import %> для импорта пространства имен MvcApplication1.Helpers. Если не импортировать это пространство имен, метод RenderBanner() не будет отображаться в качестве метода в свойстве Html.

Листинг 5. Views\Home\Index.aspx (с методом RenderBanner()

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="MvcApplication1.Views.Home.Index" %>
<%@ Import Namespace="MvcApplication1.Models" %>
<%@ Import Namespace="MvcApplication1.Helpers" %>
<!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>Index</title>
</head>
<body>
    <div>

    <% Response.WriteSubstitution(News.RenderNews); %>
    
    <hr />
    
    <% Html.RenderBanner(); %>
    
    <hr />
    
    The content of this page is output cached.
    <%= DateTime.Now %>

    </div>
</body>
</html>

При запросе страницы, отображаемой представлением в листинге 5, с каждым запросом отображается другое объявление баннера (см. рис. 2). Страница кэшируется, но объявление баннера внедряется динамически вспомогательным методом RenderBanner().

Рис. 2. Представление индекса, отображающее случайное баннерное объявление

clip_image004

Итоги

В этом руководстве объясняется, как динамически обновлять содержимое на кэшированных страницах. Вы узнали, как использовать метод HttpResponse.WriteSubstitution() для включения динамического содержимого в кэшированную страницу. Вы также узнали, как инкапсулировать вызов метода WriteSubstitution() во вспомогательном методе HTML.

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