向缓存页添加动态内容 (C#)

Microsoft

了解如何在同一页中混合动态内容和缓存内容。 通过缓存后替换,可以在已缓存输出的页面内显示动态内容,例如横幅广告或新闻项目。

利用输出缓存,可以显著提高 ASP.NET MVC 应用程序的性能。 无需在每次请求页面时重新生成一个页面,而是可以生成一次页面,并在内存中为多个用户缓存。

但有一个问题。 如果需要在页面中显示动态内容,该怎么办? 例如,假设你想要在页面中显示横幅广告。 你不希望缓存横幅广告,以便每个用户都能看到完全相同的广告。 这样你就不会赚到钱了!

幸运的是,有一个简单的解决方案。 可以利用称为 缓存后替换的 ASP.NET 框架的功能。 通过缓存后替换,可以替换已在内存中缓存的页面中的动态内容。

通常,使用 [OutputCache] 属性输出页缓存时,该页将缓存在服务器和客户端上, (Web 浏览器) 。 使用缓存后替换时,页面仅在服务器上缓存。

使用缓存后替换

使用缓存后替换需要两个步骤。 首先,需要定义一个方法,该方法返回一个字符串,该字符串表示要在缓存页中显示的动态内容。 接下来,调用 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 MVC HtmlHelper 类,以便你可以像任何其他帮助程序方法一样在视图中调用 Html.RenderBanner () 。

RenderBanner () 方法调用 HttpResponse.WriteSubstitution () 方法,并将 RenderBannerInternal () 方法传递给 WriteSubstitution () 方法。

RenderBannerInternal () 方法是专用方法。 此方法不会作为帮助程序方法公开。 RenderBannerInternal () 方法从三个横幅广告图像列表中随机返回一个横幅广告图像。

清单 5 中修改后的索引视图演示了如何使用 RenderBanner () 帮助程序方法。 请注意,视图顶部包含一个额外的 <%@ Import %> 指令,用于导入 MvcApplication1.Helpers 命名空间。 如果忽略导入此命名空间,则 RenderBanner () 方法将不会在 Html 属性上显示为方法。

列表 5 - Views\Home\Index.aspx (with RenderBanner () method)

<%@ 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 () 方法在缓存页中注入动态内容。 你还了解了如何在 HTML 帮助程序方法中封装对 WriteSubstitution () 方法的调用。

尽可能利用缓存 - 它可能会对 Web 应用程序的性能产生巨大影响。 如本教程中所述,即使需要在页面中显示动态内容,也可以利用缓存。