二、使用输出缓存
那么,现在我们假设这个读取员工的数据很频繁,但是数据又更新不是很频繁,我们就会想到,能不能对这部分数据进行缓存,以便减少每次执行的时间。
是的,我们可以这么做,而且也很容易做到这一点。MVC中内置了一个OutputCache的ActionFilter,我们可以将它应用在某个Action或者ChildAction上面
【备注】ChildAction是MVC3的一个新概念,本质上就是一个Action,但通常都是返回一个PartialView。通常这类Action,可以加上一个ChildActionOnly的ActionFilter以标识它只能作为Child被请求,而不能直接通过地址请求。
【备注】我们确实可以在Controller级别定义输出缓存,但我不建议这么做。缓存是要经过考虑的,而不是不管三七二十一就全部缓存起来。缓存不当所造成的问题可能比没有缓存还要大。
下面的代码启用了Index这个Action的缓存功能,我们让他缓存10秒钟。
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MvcApplicationCacheSample.Models;
namespace MvcApplicationCacheSample.Controllers
{
public class HomeController : Controller
{
//
// GET: /Home/
[OutputCache(Duration=10)]
public ActionResult Index()
{
//这里目前作为演示,是直接硬编码,实际上可能是读取数据库的数据
var employees = new[]{
new Employee(){ID=1,Name="ares",Gender="Male"}
};
return View(employees);
}
}
}
那么,也就是说,第一次请求这个Index的时候,里面的代码会执行,并且结果会被缓存起来,然后在10秒钟内,第二个或者后续的请求,就不需要再次执行,而是直接将结果返回给用户即可。
这个OutputCache的Attribute,实际上是一个ActionFilter,它有很多参数,具体的请参考http://msdn.microsoft.com/zh-cn/library/system.web.mvc.outputcacheattribute.aspx
这些参数中,Duration是必须的,这是设置一个过期时间,以秒为单位,这个我想大家都很好理解。我重点要一下下面几个:VaryByContentEncoding、VaryByCustom、VaryByHeader、VaryByParam。
这四个参数的意思是,决定缓存中如何区分不同请求,就是说,哪些因素将决定使用还是不使用缓存。默认情况下,如果不做任何设置,那么在规定的时间内(我们称为缓存期间),所有用户,不管用什么方式来访问,都是直接读取缓存。
VaryByParam,可以根据用户请求的参数来决定是否读取缓存。这个参数主要指的就是QueryString。例如
如果有多个参数的话,可以用逗号分开他们。例如 VaryByParam=”name,Id”
【备注】这里其实会有一个潜在的风险,由于针对不同的参数(以及他们的组合)需要缓存不同的数据版本,假设有一个恶意的程序,分别用不同的参数发起大量的请求,那么就会导致缓存爆炸的情况,极端情况下,会导致服务器出现问题。(当然,IIS里面,如果发现缓存的内容不够用了,会自动将一些数据清理掉,但这就同样导致了程序的不稳定性,因为某些正常需要用的缓存可能会被销毁掉)。这也就是我为什么强调说,缓存设计是一个比较复杂的事情。
VaryByHeader,可以根据用户请求中所提供的一些Header信息不同而决定是否读取缓存。我们可以看到在每个请求中都会包含一些Header信息,如下图所示

这个也很有用,例如根据不同的语言,我们显然是有不同的版本的。或者根据用户浏览器不同,也可以缓存不同的版本。可以通过这样设置
上面两个是比较常用的。当然还有另外两个属性也可以设置