一、MVC缓存简介
缓存是将信息(数据或页面)放在内存中以避免频繁的数据库存储或执行整个页面的生命周期,直到缓存的信息过期或依赖变更才再次从数据库中读取数据或重新执行页面的生命周期。在系统优化过程中,缓存是比较普遍的优化做法和见效比较快的做法。
MVC缓存本质上还是.NET的一套缓存体系,只不过该缓存体系应用在了MVC框架上。下面的示例把缓存应用在MVC上。
缓存的常用场景:
数据被频繁的使用,并且很少发生变化或对即时性的要求不高。
二、Control缓存
Control缓存即是把缓存应用到整个Control上,该Control下的所有Action都会被缓存起来。Control缓存的粒度比较粗,应用也比较少些。
1 使用系统; 2 using System.Collections.Generic; 3 使用System.Linq; 4 使用System.Web; 5 使用System.Web.Mvc; 6 7 namespace MvcCache.Control.Controllers 8 { 9 [OutputCache(Duration = 10 )] 10 public class ControlController:Controller 11 { 12 // 13 // GET:/ Home / 14 public ActionResult Index() 15 { 16 ViewBag.CurrentTime = System.DateTime.Now; 17 返回View(); 18 } 19 20 public ActionResult Index1 () 21 { 22 ViewBag.CurrentTime = System.DateTime.Now; 23 return View(); 24 } 25 26 } 27 }
在名为Control的Control中加入了OutputCache,并设置持续时间为10秒(Duration=10),即每10秒后过期当再次触发时更新缓存。下面是View中的代码,打印ViewBag的时间。
1 @ { 2 ViewBag.Title =“Index”; 3 } 4 5 < h2 > @ ViewBag.CurrentTime </ h2 > 6 7 @ { 8 ViewBag.Title =“Index1”; 9 } 10 11 < h2 > @ ViewBag.CurrentTime </ h2 >
三、Action缓存
即把缓存用到Action上,Action缓存为比较常用的缓存方式,该方式粒度细一些。使用方法类似Control缓存。
1 使用系统; 2 using System.Collections.Generic; 3 使用System.Linq; 4 使用System.Web; 5 使用System.Web.Mvc; 6个 7 命名空间MvcCache.Control.Controllers 8 { 9 // 控制不加缓存 10 公共 类的ActionController:控制器 11 { 12 // 该指数的动作加缓存 13 [的OutputCache(持续时间= 10 )] 14 公共的ActionResult指数() 15 { 16 ViewBag.CurrentTime = System.DateTime.Now; 17 return View(); 18 } 19 20 //该Action不加缓存 21 public ActionResult Index1() 22 { 23 ViewBag.CurrentTime = System.DateTime.Now; 24 return View(); 25 } 26 27 } 28 }
Index加入了缓存,而Index1没有加。此时Index1每次刷新页面都会取到当前的时间并打印。
1 @ { 2 ViewBag.Title =“Index”; 3 4 } 5 6 < h2 > @ ViewBag.CurrentTime </ h2 > 7 8 @ { 9 ViewBag.Title =“Index1”; 10 } 11 12 < h2 > @ ViewBag.CurrentTime </ h2 >
四、使用配置文件
当我们需要将N个Control或Action加入缓存,并且缓存的参数是一致的情况下,我们可以把相关的设置放到Web.config中,并在程序中加入相应的配置。
1 <?XML版本= “1.0”编码= “UTF-8” ?> 2 <! - 3 有关如何配置ASP.NET应用程序的更多信息,请访问: 4 http://go.microsoft.com/fwlink/? LinkId = 169433 5 - > 6 7 < configuration > 8 < appSettings > 9 < add key =“webpages:Version” value =“2.0.0.0” /> 10 < add key =“webpages:Enabled” value =“false” /> =“PreserveLoginUrl” value =“true” /> 12 < add key =“ClientValidationEnabled” value =“true” /> 13 < add key =“UnobtrusiveJavaScriptEnabled” value =“true” /> 14 </ appSettings > 15 < system。 web > 16 <! - 配置缓存- > 17 < caching > 18 < outputCacheSettings > 19 <outputCacheProfiles > 20 < addname =“TestConfigCache” duration =“10” /> 21 </ outputCacheProfiles > 22 </ outputCacheSettings > 23 </ caching > 24 <! - 配置缓存- > 25 < httpRuntime targetFramework =“4.5” /> 26 < compilation debug =“true” targetFramework =“4.5” /> 27 < pages > 28 < namespaces > 29 <添加命名空间=“System.Web.Helpers” /> 30 < add namespace =“System.Web.Mvc” /> 31 < add namespace =“System.Web.Mvc.Ajax” /> 32 < add namespace =“System.Web。 Mvc.Html“ /> 33 < add namespace =”System.Web.Routing“ /> 34 < add namespace =”System.Web.WebPages“ /> 35 </ namespaces > 36 </ pages > 37 </ system.web > 38 <system.webServer > 39 < validation validateIntegratedModeConfiguration =“false” /> 40 41 < handlers > 42 < remove name =“ExtensionlessUrlHandler-ISAPI-4.0_32bit” /> 43 < remove name =“ExtensionlessUrlHandler-ISAPI-4.0_64bit” /> 44 < remove name =“ExtensionlessUrlHandler-Integrated-4.0” /> 45 < add name =“ExtensionlessUrlHandler-ISAPI-4.0_32bit” path =“*。“ 动词=“GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS” modules =“IsapiModule” scriptProcessor =“%windir%\ Microsoft.NET \ Framework \ v4.0.30319 \ aspnet_isapi.dll” preCondition =“classicMode,runtimeVersionv4 .0,bitness32“ responseBufferLimit =”0“ /> 46 < add name =”ExtensionlessUrlHandler-ISAPI-4.0_64bit“ path =”*。“ 动词= “GET,HEAD,POST,DEBUG,PUT,DELETE,贴剂,OPTIONS” 模块= “IsapiModule” scriptProcessor = “%WINDIR%\ Microsoft.NET \ Framework64 \ v4.0.30319 \ ASPNET_ISAPI.DLL” 前提=”responseBufferLimit =“0” /> 47 < add name =“ExtensionlessUrlHandler-Integrated-4.0” path =“*。” verb =“GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS” type =“System.Web.Handlers.TransferRequestHandler” preCondition =“integratedMode,runtimeVersionv4.0” /> 48 </ handlers > 49 </ system .webServer > 50 51 </ configuration >
配置缓存节只需要将其放在system.web节下即可,下面是使用的方法
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 using System.Web.Mvc; 6 7 namespace MvcCache.Control.Controllers 8 { 9 public class ConfigController : Controller 10 { 11 //TestConfigCache为在配置文件中配置的缓存节 12 [OutputCache(CacheProfile = "TestConfigCache")] 13 public ActionResult Index() 14 { 15 ViewBag.CurrentTime = System.DateTime.Now; 16 返回View(); 17 } 18 19 } 20 }
注:当Control与Action都应用了缓存时,以Action的缓存为主。
五、OutputCache参数简介
下面代码为mvc4的OutputCache的定义,由于使用的是英文版本IDE和框架,因此注释全部为英文。后面的讲解主要讲解常用的属性,对于缓存依赖这个重点内容在下面单独讲解使用方法。
如果想了解各个属性的详细说明及使用请查阅MSDN,链接地址如下:https://msdn.microsoft.com/zh-cn/library/system.web.mvc.outputcacheattribute.aspx
1 使用系统; 2 使用System.Web.UI; 3 4 名称空间System.Web.Mvc 5 { 6 // 摘要: 7 // 表示一个属性,用于标记输出为 8 // 的动作方法 将被缓存。 9 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,Inherited = true,AllowMultiple = false )] 10 公共 类OutputCacheAttribute:ActionFilterAttribute,IExceptionFilter 11 { 12 // 摘要: 13 // 初始化System.Web.Mvc.OutputCacheAttribute类的新实例。 14 public OutputCacheAttribute(); 15 16 // 摘要: 17 // 获取或设置缓存配置文件名称。 18 // 19 // 返回值: 20 // 缓存配置文件名称。 21 公共 字符串 CacheProfile { get ; 设置; } 22 // 23 // 总结: 24 // 获取或设置子动作缓存。 25 // 26 // 返回: 27 // 子动作缓存。 28 public static System.Runtime.Caching.ObjectCache ChildActionCache { get ; 设置; } 29 // 30 // 摘要: 31 // 获取或设置缓存持续时间,以秒为单位。 32 // 33 // 返回值: 34 // 缓存持续时间。 35 public int Duration { get ; 组; } 36 // 37 // 摘要: 38 // 获取或设置位置。 39 // 40 // 返回值: 41 // 位置。 42 public OutputCacheLocation Location { get ; 设置; } 43 // 44 // 摘要: 45 // 获取或设置一个指示是否存储缓存的值。 46 // 47 // 返回值: 48 // 如果应该存储缓存,则为true; 否则,是错误的。 49 public bool NoStore { get ; 设置; } 50 // 51 // 摘要: 52 // 获取或设置SQL依赖项。 53 // 54 // 返回值: 55 // SQL依赖关系。 56 公共 字符串 SqlDependency { get ; 设置; } 57 // 58 // 摘要: 59 // 获取或设置变化内容编码。 60 // 61 //返回: 62 // 内容不同的编码。 63 public string VaryByContentEncoding { get ; 设置; } 64 // 65 // 摘要: 66 // 获取或设置变化的自定义值。 67 // 68 // 返回值: 69 // 变化的自定义值。 70 公共 字符串 VaryByCustom { get ; 设置; } 71 // 72 // 总结: 73 // 获取或设置不同的标题值。 74 // 75 // 返回值: 76 // 不同的报头值。 77 public string VaryByHeader { get ; 设置; } 78 // 79 // 摘要: 80 // 获取或设置参数的变化值。 81 // 82 // 返回值: 83 // 参数变化值。 84 public string VaryByParam { get ; 设置; } 85 86 // 摘要: 87 // 返回一个值,该值指示子动作高速缓存是否处于活动状态。 88 // 89 // 参数: 90 // controllerContext: 91 // 控制器上下文。 92 // 93 // 返回值: 94 // 如果子动作缓存处于活动状态,则为true; 否则,是错误的。 95 公共 静态 布尔IsChildActionCacheActive(ControllerContext controllerContext); 96 // 97 // 总结: 98 // 此方法是System.Web.Mvc.IActionFilter.OnActionExecuted(System.Web.Mvc.ActionExecutedContext) 99的实现 // 并且支持ASP.NET MVC基础结构。它不打算 直接从您的代码中使用 100 // 。 101 // 102 // 参数: 103 // filterContext: 104 // 过滤器上下文。 105 public override void OnActionExecuted(ActionExecutedContext filterContext); 106 // 107 // 总结: 108 // 此方法是System.Web.Mvc.IActionFilter.OnActionExecuting(System.Web.Mvc.ActionExecutingContext) 109的实现 // 并且支持ASP.NET MVC基础结构。它不打算 直接从您的代码中使用 110 // 。 111 // 112 // 参数: 113 // filterContext: 114 // 过滤器上下文。 115 公共 覆盖 空隙OnActionExecuting(ActionExecutingContext filterContext); 116 // 117 // 总结: 118 // 此方法是System.Web.Mvc.IExceptionFilter.OnException(System.Web.Mvc.ExceptionContext) 119的实现 // 并且支持ASP.NET MVC基础结构。它不打算 直接从您的代码中使用 120 // 。 121 // 122 // 参数: 123 // filterContext: 124 // 过滤器上下文。 125 public void OnException(ExceptionContext filterContext); 126 // 127 // 总结: 128 // 此方法是System.Web.Mvc.IResultFilter.OnResultExecuted(System.Web.Mvc.ResultExecutedContext) 129的实现 // 并且支持ASP.NET MVC基础结构。它不打算 直接从您的代码中使用 130 // 。 131 // 132 // 参数: 133 // filterContext: 134 // 过滤器上下文。 135 public override void OnResultExecuted(ResultExecutedContext filterContext); 136 // 137 // 总结: 138 // 在执行结果之前调用。 139 // 140 // 参数: 141 // filterContext: 142 // 过滤器上下文,它封装了使用System.Web.Mvc.AuthorizeAttribute的信息。 143 // 144 // 异常: 145 // System.ArgumentNullException: 146 // filterContext参数为null。 147 公共 覆盖 空隙OnResultExecuting(ResultExecutingContext filterContext); 148 } 149 }
常用属性:
1)CacheProfile:缓存使用的配置文件的缓存名称。
2)Duration:缓存时间,以秒为单位,这个除非你的Location=None,可以不添加此属性,其余时候都是必须的。
3)OutputCacheLocation:枚举类型,缓存的位置。当设置成None时,所有缓存将失效,默认为Any。
Any:页面被缓存在浏览器、代理服务器端和web服务器端;
Client:缓存在浏览器;
DownStream:页面被缓存在浏览器和任何的代理服务器端;
Server:页面被缓存在Web服务器端;
None:页面不缓存;
ServerAndClient:页面被缓存在浏览器和web服务器端;
4)VaryByParam:用于多个输出缓存的字符串列表,并以分号进行分隔。默认时,该字符串与GET方法传递的参数或与POST方法传递的变量相对应。当被设置为多个参数时,输出缓存将会为每个参数都准备一个与之相对应的文档版本。可能值包括none,*,以及任何有效的查询串或POST参数名称。
如果您不想要为不同的已缓存内容指定参数,可以将其设置为none。如果想要指定所有的已缓存内容参数,可以设置为*。
六、缓存依赖
SqlDependency:一个值,用于标识操作的输出缓存所依赖的一组数据库名称和表名称对。SqlCacheDependency 类在所有受支持的 SQL Server 版本 (7.0, 2000, 2005) 上监视特定的 SQL Server 数据库表,数据库表发生更改时,将自动删除缓存项,并向 Cache 中添加新版本的项。
概念理解起来很简单,主要是如何应用。下面为应用实例。示例说明:数据库为本地数据库,库名:wcfDemo(写wcf教程时用的库,懒了,直接用了),监听表名:user。缓存时间为:3600秒即一小时。数据库依赖周期为500毫秒,即每0.5秒监听下数据库是否有变化,如果有变化则立即更新缓存。
第一步:建立Control,测试代码如下:
1 使用系统; 2 using System.Collections.Generic; 3 使用System.Linq; 4 使用System.Web; 5 使用System.Web.Mvc; 6个 7 命名空间MvcCache.Control.Controllers 8 { 9 公共 类SqlDependencyController:控制器 10 { 11 [的OutputCache(CacheProfile = “ SqlDependencyCache ” )] 12 公共的ActionResult指数() 13 { 14 ViewBag.CurrentTime = System.DateTime.Now; 15 返回View(); 16 } 17 18 } 19 }
第二步,在配置文件中配置CacheProfile为SqlDependencyCache的节,并且配置缓存对数据库的依赖。
1 <?XML版本= “1.0”编码= “UTF-8” ?> 2 <! - 3 有关如何配置ASP.NET应用程序的更多信息,请访问: 4 http://go.microsoft.com/fwlink/? LinkId = 169433 5 - > 6 7 < configuration > 8 <! - 数据库连接字符串- > 9 < connectionStrings > 10 < add name =“Conn” connectionString =“server = localhost; database = wcfDemo; uid = sa ; PWD = 123456;” providerName =“System.Data.SqlClient” connectionStrings > 12 <! - 数据库连接字符串- > 13 < appSettings > 14 < add key =“webpages:Version” value =“2.0.0.0” /> 15 < add key =“webpages:Enabled” value =“ false“ /> 16 < add key =”PreserveLoginUrl“ value =”true“ /> 17 < add key =”ClientValidationEnabled“ value =”true“ /> 18 < 添加键=“UnobtrusiveJavaScriptEnabled” value =“true” /> 19 </ appSettings > 20 < system.web > 21 <! - 配置缓存- > 22 < 缓存> 23 < sqlCacheDependency > <! - 缓存的数据库依赖节- - > 24 < databases > 25 < add name =“UserCacheDependency” connectionStringName =“Conn” pollTime =“500” /> <!--Conn:数据库连接字符串的名称,name随便启名,缓存节会用到--> 26 </databases> 27 </sqlCacheDependency> 28 <outputCacheSettings> 29 <outputCacheProfiles> 30 <add name="SqlDependencyCache" duration="3600" sqlDependency="UserCacheDependency:user"/><!--UserCacheDependency:数据库依赖配置节的名称,user:数据库中需要监听的表名称--> 31 </outputCacheProfiles> 32 </outputCacheSettings> 33 </caching> 34 <!--配置缓存- > 35 < httpRuntime targetFramework =“4.5” /> 36 < compilation debug =“true” targetFramework =“4.5” /> 37 < pages > 38 < namespaces > 39 < add namespace =“System.Web.Helpers” /> 40 < add namespace =“System.Web.Mvc” /> 41 < add namespace =“System.Web.Mvc.Ajax” /> 42 <添加命名空间=“System.Web.Mvc.Html” /> 43 < add namespace =“System.Web.Routing” /> 44 < add namespace =“System.Web.WebPages” /> 45 </ namespaces > 46 </ pages > 47 </ system.web > 48 < system.webServer > 49 < validation validateIntegratedModeConfiguration =“false” /> 50 51 < handlers > 52 <删除名称=“ExtensionlessUrlHandler-ISAPI-4.0_32bit” /> 53 < remove name =“ExtensionlessUrlHandler-ISAPI-4.0_64bit” /> 54 < remove name =“ExtensionlessUrlHandler-Integrated-4.0” /> 55 < add name =“ExtensionlessUrlHandler-ISAPI- 4.0_32bit“ path =”*“。动词= “GET,HEAD,POST,DEBUG,PUT,DELETE,贴剂,OPTIONS” 模块= “IsapiModule” scriptProcessor = “%WINDIR%\ Microsoft.NET \框架\ v4.0.30319 \ ASPNET_ISAPI.DLL” 前提=“classicMode, runtimeVersionv4.0, /> 56 < add name =“ExtensionlessUrlHandler-ISAPI-4.0_64bit” path =“*。” verb =“GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS” modules =“IsapiModule” scriptProcessor =“%windir%\ Microsoft.NET \ Framework64 \ v4.0.30319 \ aspnet_isapi.dll” preCondition =“classicMode, runtimeVersionv4.0,bitness64“ responseBufferLimit =”0“ /> 57 < add name =”ExtensionlessUrlHandler-Integrated-4.0“ path =”*。“ verb =“GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS”preCondition =“integratedMode,runtimeVersionv4.0” /> 58 </ handlers > 59 </ system.webServer > 60 61 </ configuration >
注意:
1)由于是缓存对数据库的依赖,此外必须包含connectionStrings的节。
2)<add name =“UserCacheDependency”connectionStringName =“Conn”pollTime =“500”/>
connectionStringName:数据库连接字符串的名称
pollTime:监听数据库变化的周期,以毫秒为单位。即每500毫秒查看下数据库是否有变化。
3)<add name =“SqlDependencyCache”duration =“3600”sqlDependency =“UserCacheDependency:user”/>
sqlDependency:数据依赖的节的名称+冒号+数据表名称(小写)。如果这个依赖会用到多个表,则用分号间隔开,如下所示UserCacheDependency:user;UserCacheDependency:user1
第三步:启用该数据库表的缓存依赖通知功能
打开vs命令工具行,输入:aspnet_regsql -S localhost -U sa -P 123456 -ed -d wcfDemo -et -t user
-S localhost:数据库地址
-U sa:数据库登录名
-P 123456:数据库登录密码
-d wcfDemo:数据库的名称
-t user:表名称(小写)
因为只是监听是否发生数据变化,因此表结构随意,下面的我的表结构:
第四步:测试程序,上面的例子只打印了当前时间,如果不加入缓存依赖的情况下,1小时之内都应该运行出的结果都是当前时间,每次Ctrl+F5强制刷新浏览器时不发生任务变化。当加入缓存依赖后,只要对数据库的数据进行任意修改都会更新缓存的时间,即更改数据后再刷新浏览器时会看到时间在变化。