技术开发 频道

ASP.NET MVC 3:缓存功能的设计问题

  二、使用输出缓存

  那么,现在我们假设这个读取员工的数据很频繁,但是数据又更新不是很频繁,我们就会想到,能不能对这部分数据进行缓存,以便减少每次执行的时间。

  是的,我们可以这么做,而且也很容易做到这一点。MVC中内置了一个OutputCache的ActionFilter,我们可以将它应用在某个Action或者ChildAction上面

  【备注】ChildAction是MVC3的一个新概念,本质上就是一个Action,但通常都是返回一个PartialView。通常这类Action,可以加上一个ChildActionOnly的ActionFilter以标识它只能作为Child被请求,而不能直接通过地址请求。

  【备注】我们确实可以在Controller级别定义输出缓存,但我不建议这么做。缓存是要经过考虑的,而不是不管三七二十一就全部缓存起来。缓存不当所造成的问题可能比没有缓存还要大。

  下面的代码启用了Index这个Action的缓存功能,我们让他缓存10秒钟。

using System;
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。例如

如果我们缓存了http://localhost/Home/Index,那么用这个地址来访问的时候,规定时间内都是读取缓存。但如果用http://localhost/Home/Index?name=chenxizhang这样的地址过来访问,显然我们希望不要读取缓存,因为参数不一样了。要实现这样的需求,也就是说,希望根据name参数的不同缓存不同的数据。则可以设置VaryByParam=”name”。

如果有多个参数的话,可以用逗号分开他们。例如 VaryByParam
=”name,Id”

   【备注】这里其实会有一个潜在的风险,由于针对不同的参数(以及他们的组合)需要缓存不同的数据版本,假设有一个恶意的程序,分别用不同的参数发起大量的请求,那么就会导致缓存爆炸的情况,极端情况下,会导致服务器出现问题。(当然,IIS里面,如果发现缓存的内容不够用了,会自动将一些数据清理掉,但这就同样导致了程序的不稳定性,因为某些正常需要用的缓存可能会被销毁掉)。这也就是我为什么强调说,缓存设计是一个比较复杂的事情。

  VaryByHeader,可以根据用户请求中所提供的一些Header信息不同而决定是否读取缓存。我们可以看到在每个请求中都会包含一些Header信息,如下图所示

  这个也很有用,例如根据不同的语言,我们显然是有不同的版本的。或者根据用户浏览器不同,也可以缓存不同的版本。可以通过这样设置

VaryByHeader=”Accept-Language,User-Agent”

   上面两个是比较常用的。当然还有另外两个属性也可以设置

0
相关文章