ASP.NET MVC 缓存入门教程






4.90/5 (46投票s)
本文将介绍如何在 ASP.NET MVC 应用程序中实现缓存。
引言
本文将介绍如何在 ASP.NET MVC 应用程序中实现缓存。
背景
作为 ASP.NET Web 开发者,我们主要负责开发动态网页,即内容来自数据库、服务器目录、XML 文件或其他网站。缓存是指将频繁使用的内容存储在内存中,以提高性能。
为什么我们要关心缓存?让我们设想一个场景:网页的内容是从数据库中获取的。用户根据某些条件请求内容。如果数据库频繁更改,即使在同一用户两次请求之间,我们也能预期数据库会发生变化,那么我们就无法缓存用户请求的数据。但是,如果数据库更改的频率不高,我们可以实施一些缓存策略,以便当用户频繁请求相同数据时,我们不必每次都访问数据库(因为我们知道内容没有改变)。
这里的两个关键术语是“频率”和“条件”。频率是指我们预期用户请求特定页面的次数,而条件是决定页面显示结果唯一性的因素。
频率很重要,因为我们需要确定数据库更改的间隔,并将其与用户请求的频率进行比较,以便实施缓存,同时确保用户不会看到过时的数据。
条件很重要,因为我们需要确保为每个唯一条件都实现了页面缓存。不能出现用户根据 `criteria01` 请求内容,而我们却显示给他之前缓存的 `criteria00` 的结果(为他之前缓存的)。
带着这些理论知识,让我们开始看看如何在 ASP.NET MVC 中实现缓存。
注意:我曾撰写过一篇关于 ASP.NET Web Forms 缓存的文章。本文专门讨论 ASP.NET MVC 中的缓存。由于这两种技术背后的缓存理论概念是相同的,我从那篇文章中借鉴了一些内容。该文章可以在这里找到:ASP.NET 缓存入门教程[^]
使用代码
缓存类型
ASP.NET 提供两种缓存类型:
- 页面输出缓存
- 应用程序缓存
页面输出缓存
页面输出缓存是指 Web 服务器在用户请求后将特定网页缓存到内存中的能力,以便后续对同一页面的请求会检查缓存页面的有效性,而不会导致资源使用(数据库访问或文件访问),页面将从缓存返回给用户。
让我们开发一个小型应用程序来演示如何在 ASP.NET MVC 中实现页面输出缓存。我们实现一个简单的视图,向用户显示当前时间。`Controller` 代码只是返回视图。
public class TestController : Controller
{
public ActionResult Index()
{
return View();
}
}
在我的视图中,我向用户显示当前时间。
@{
ViewBag.Title = "Caching Demo";
}
Time is @DateTime.Now.ToString()
如果现在运行此应用程序,它将显示当前的日期和时间。如果刷新,时间也会更新(因为目前没有实现缓存)。
现在,假设此页面应缓存 30 秒,即时间字符串在 30 秒内不应更改。我们可以通过在操作方法上添加 `OutputCache` 属性来实现。我们将向该属性传递两个值:第一个是缓存的 `Duration`,第二个是 `VaryByParam` 属性。`VaryByParam="none"` 指定缓存不依赖于任何内容。
public class TestController : Controller
{
[OutputCache(Duration=30, VaryByParam="none")]
public ActionResult Index()
{
return View();
}
}
现在,如果我们运行页面并刷新它,时间将在 30 秒内不会改变。
在上面的示例中,我们指定了 `VaryByParam="none"`。这样做可能导致用户看到过时的数据。因此,如果我们想基于屏幕上的用户选择来使缓存失效,我们可以指定 `VaryByParam` 的值。因此,如果我想为具有不同查询字符串的页面请求缓存不同的值,我可以将 varyByParam 的值指定为该查询字符串的名称(或任何我想使用的 HTML 元素)。
public class TestController : Controller
{
[OutputCache(Duration = 30, VaryByParam = "none")]
public ActionResult Index()
{
return View();
}
[OutputCache(Duration = 30, VaryByParam = "id")]
public ActionResult Index1()
{
return View();
}
}
现在,如果我们运行应用程序并导航到 Index1,我将看到每个“id”查询字符串值的缓存版本。
所以我们看到的是,我们可以指定页面应缓存的 `Duration`,这与我们之前讨论的频率有关。`Duration` 的选择应确保在此期间我们不期望数据发生任何变化;对于条件,我们看到了如何使用 `VaryByParam` 来确保为每个不同的条件生成输出,并且不会仅仅向用户展示相同的缓存副本。
如果我们基于任何/所有 HTML 元素的变化需要不同的输出页面,我们可以指定 `VaryByParam ="*"` 列表。让我们看一下可以用来定制缓存行为的其他参数。
- `VaryByParam`:通过 HTTP POST/GET 发送到服务器的字符串列表,用于验证缓存。
- `VaryByCustom`:用于自定义输出缓存需求。
- `VaryByHeader`:决定缓存有效性的 HTTP 头。
- `SqlDependency`:定义缓存有效性所依赖的数据库表名对。
缓存位置
`OutputCache` 属性类还有一个重要的属性是 `Location`。此属性将确定缓存数据存储在服务器上的位置。此属性的可能值可以是:
- `Any`(默认):内容缓存到三个位置:Web 服务器、任何代理服务器和 Web 浏览器。
- `Client`:内容缓存到 Web 浏览器。
- `Server`:内容缓存到 Web 服务器。
- `ServerAndClient`:内容缓存到 Web 服务器和 Web 浏览器。
- `None`:内容不缓存到任何地方。
指定缓存属性的更智能方法
如果所有操作方法都有相同的缓存需求,而不是在所有单独的操作方法上添加此属性,我们可以直接在控制器上添加此属性,缓存将对所有操作方法生效。
[OutputCache(Duration = 30, VaryByParam = "none")]
public class TestController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult Index1()
{
return View();
}
}
如果跨控制器有多个操作方法需要相同的缓存行为,我们可以将这些缓存值放在 `web.config` 中,并为其创建一个 `cacheprofile`。
<caching>
<outputCacheSettings>
<outputCacheProfiles>
<add name="MyCacheProfile"
duration="30"
varyByParam="id"
location="Any" />
</outputCacheProfiles>
</outputCacheSettings>
</caching>
要在操作方法中使用这些值,我们只需在操作方法中指定 `CacheProfile` 名称即可。
[OutputCache(CacheProfile = "MyCacheProfile")]
public ActionResult Dummy()
{
return View();
}
局部页面缓存
在 ASP.NET Web Forms 中,我们需要创建自定义用户控件才能实现局部页面缓存。在 MVC 中,可以通过创建简单的局部视图来实现相同的功能。该局部视图中的缓存将由负责在此局部视图中渲染数据的操作方法关联的 `OutputCache` 属性控制。
为了说明这一点,让我们在控制器中再创建一个操作方法 `Index2`。此操作不会缓存数据。我们将在 `Index2` 视图中渲染一个局部视图。该局部视图将缓存时间 10 秒。让我们看看这些操作方法。
public ActionResult Index2()
{
return View();
}
[OutputCache(Duration = 10, VaryByParam = "none")]
public PartialViewResult PartialTest()
{
return PartialView("SamplePartial");
}
`Index2` 视图如下所示:
@{
ViewBag.Title = "Caching Demo";
}
Time is @DateTime.Now.ToString()
<br /><br />
Partial page here: @Html.Action("PartialTest")
最后是局部视图代码:
Time: @DateTime.Now.ToString()
现在,如果我们运行应用程序并导航到 `Index2`,我们可以看到主页的时间没有被缓存,但是来自局部视图的时间被缓存了 10 秒。
应用程序缓存
应用程序数据缓存是存储缓存数据对象的机制。它与页面缓存无关。ASP.NET 允许我们将对象存储在基于键值对的缓存中。我们可以使用它来存储需要缓存的数据。让我们用同一个示例来尝试现在将 `DateTime` 字符串存储在应用程序 `Cache` 中。
让我们创建一个操作方法,它将从应用程序缓存中显示视图中的日期。
public ActionResult Index3()
{
if (System.Web.HttpContext.Current.Cache["time"] == null)
{
System.Web.HttpContext.Current.Cache["time"] = DateTime.Now;
}
ViewBag.Time = ((DateTime)System.Web.HttpContext.Current.Cache["time"]).ToString();
return View();
}
与此操作方法对应的视图是:
@{
ViewBag.Title = "Caching Demo";
}
Time is @ViewBag.Time
现在,如果我们运行应用程序并导航到 `Index3`,我们将看到时间。但是,无论我们刷新此页面多少次,时间值都不会改变。因为该值来自应用程序缓存。而且,我们根本没有使缓存失效。
应用程序数据缓存有各种参数,可用于使值失效并控制其行为。
- `Dependencies`:缓存中的任何文件或项,会使此缓存项失效。
- `absoluteExpiration`:应从缓存中删除此对象的绝对时间。
- `slidingExpiration`:应从缓存中删除此对象的相对时间。
- `priority`:定义项的优先级。这在服务器内存不足时很有用,因为在这种情况下,它会首先开始删除优先级最低的缓存项。
- `onRemoveCallBack`:这是当对象从缓存中移除时将被调用的事件处理程序。它为我们提供了一个采取进一步措施的地方。
关注点
在本文中,我们了解了如何在 ASP.NET 应用程序中实现缓存。示例解决方案包含讨论主题的完整工作示例。此解决方案已启用 Nuget 包还原,因此应用程序将在构建前下载依赖项。本文是从初学者的角度撰写的。希望这能帮助您。
历史
- 2014年4月9日:初稿