一、概述
緩存是將信息(數據或頁面)放在內存中以避免頻繁的數據庫存儲或執行整個頁面的生命周期,直到緩存的信息過期或依賴變更才再次從數據庫中讀取數據或重新執行頁面的生命周期。在系統優化過程中,緩存是比較普遍的優化做法和見效比較快的做法。
MVC緩存本質上還是.NET的一套緩存體系,只不過該緩存體系應用在了MVC框架上。
緩存是一種以空間換時間的技術, 比如, CPU的二級緩存,Windows的文件緩存。減少服務器的負荷,默認存放在內存里面,不過是可以修改的。緩存存在失效的情況。Asp.net 緩存主要分為頁面緩存,數據源緩存,數據緩存。
緩存代碼的位置:
[1] 頁面緩存: <%@OutPutCache Duration="15" VaryByParam="none" %>
[2] Contorller 緩存: [OutputCache(Duration = 10)]
[3] Action 緩存: [OutputCache(Duration = 10)]
緩存的常用場景:
數據被頻繁的使用,並且很少發生變化或對即時性的要求不高。
二、Control 緩存
Control 緩存即是把緩存應用到整個Control 上,該Control 下的所有Action都會被緩存起來。Control 緩存的粒度比較粗,應用也比較少些。
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace MvcCache.Control.Controllers { [OutputCache(Duration = 10)] public class ControlController : Controller { // GET: /Home/ public ActionResult Index() { ViewBag.CurrentTime = System.DateTime.Now; return View(); } public ActionResult Index1() { ViewBag.CurrentTime = System.DateTime.Now; return View(); } } }
在名為Control的Control中加入了OutputCache,並設置持續時間為10秒(Duration=10),即每10秒后過期當再次觸發時更新緩存。
三、Action 緩存
即把緩存用到Action上,Action緩存為比較常用的緩存方式,該方式粒度細一些。使用方法類似Control緩存。
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace MvcCache.Control.Controllers { //Control不加緩存 public class ActionController : Controller { //該Index的Action加緩存 [OutputCache(Duration = 10)] public ActionResult Index() { ViewBag.CurrentTime = System.DateTime.Now; return View(); } //該Action不加緩存 public ActionResult Index1() { ViewBag.CurrentTime = System.DateTime.Now; return View(); }
} }
四、使用配置文件
當我們需要將N個Control或Action加入緩存,並且緩存的參數是一致的情況下,我們可以把相關的設置放到Web.config中,並在程序中加入相應的配置。同時,在配置文件中配置緩存參數將更加靈活方便。
<?xml version="1.0" encoding="utf-8"?> <!-- For more information on how to configure your ASP.NET application, please visit http://go.microsoft.com/fwlink/?LinkId=169433 --> <configuration> <appSettings> <add key="webpages:Version" value="2.0.0.0" /> <add key="webpages:Enabled" value="false" /> <add key="PreserveLoginUrl" value="true" /> <add key="ClientValidationEnabled" value="true" /> <add key="UnobtrusiveJavaScriptEnabled" value="true" /> </appSettings> <system.web> <!--配置緩存--> <caching> <outputCacheSettings> <outputCacheProfiles> <add name="TestConfigCache" duration="10"/> </outputCacheProfiles> </outputCacheSettings> </caching> <!--配置緩存--> <httpRuntime targetFramework="4.5" /> <compilation debug="true" targetFramework="4.5" /> <pages> <namespaces> <add namespace="System.Web.Helpers" /> <add namespace="System.Web.Mvc" /> <add namespace="System.Web.Mvc.Ajax" /> <add namespace="System.Web.Mvc.Html" /> <add namespace="System.Web.Routing" /> <add namespace="System.Web.WebPages" /> </namespaces> </pages> </system.web> <system.webServer> <validation validateIntegratedModeConfiguration="false" /> <handlers> <remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" /> <remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" /> <remove name="ExtensionlessUrlHandler-Integrated-4.0" /> <add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="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" /> <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" /> <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" /> </handlers> </system.webServer> </configuration>
配置緩存節只需要將其放在system.web節下即可,以下是使用的方法:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace MvcCache.Control.Controllers { public class ConfigController : Controller { //TestConfigCache為在配置文件中配置的緩存節 [OutputCache(CacheProfile = "TestConfigCache")] public ActionResult Index() { ViewBag.CurrentTime = System.DateTime.Now; return View(); }
}
}
注:當Control與Action都應用了緩存時,以Action的緩存為主。
五、OutputCache 常用參數
下面代碼為mvc4的OutputCache的定義,由於使用的是英文版本IDE和框架,因此注釋全部為英文。后面的講解主要講解常用的屬性,此處不包含對於緩存依賴的講解使用方法。
各個屬性的詳細說明及使用請查閱MSDN,鏈接地址如下:https://msdn.microsoft.com/zh-cn/library/system.web.mvc.outputcacheattribute.aspx

using System; using System.Web.UI; namespace System.Web.Mvc { // Summary: // Represents an attribute that is used to mark an action method whose output // will be cached. [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)] public class OutputCacheAttribute : ActionFilterAttribute, IExceptionFilter { // Summary: // Initializes a new instance of the System.Web.Mvc.OutputCacheAttribute class. public OutputCacheAttribute(); // Summary: // Gets or sets the cache profile name. // // Returns: // The cache profile name. public string CacheProfile { get; set; } // // Summary: // Gets or sets the child action cache. // // Returns: // The child action cache. public static System.Runtime.Caching.ObjectCache ChildActionCache { get; set; } // // Summary: // Gets or sets the cache duration, in seconds. // // Returns: // The cache duration. public int Duration { get; set; } // // Summary: // Gets or sets the location. // // Returns: // The location. public OutputCacheLocation Location { get; set; } // // Summary: // Gets or sets a value that indicates whether to store the cache. // // Returns: // true if the cache should be stored; otherwise, false. public bool NoStore { get; set; } // // Summary: // Gets or sets the SQL dependency. // // Returns: // The SQL dependency. public string SqlDependency { get; set; } // // Summary: // Gets or sets the vary-by-content encoding. // // Returns: // The vary-by-content encoding. public string VaryByContentEncoding { get; set; } // // Summary: // Gets or sets the vary-by-custom value. // // Returns: // The vary-by-custom value. public string VaryByCustom { get; set; } // // Summary: // Gets or sets the vary-by-header value. // // Returns: // The vary-by-header value. public string VaryByHeader { get; set; } // // Summary: // Gets or sets the vary-by-param value. // // Returns: // The vary-by-param value. public string VaryByParam { get; set; } // Summary: // Returns a value that indicates whether a child action cache is active. // // Parameters: // controllerContext: // The controller context. // // Returns: // true if the child action cache is active; otherwise, false. public static bool IsChildActionCacheActive(ControllerContext controllerContext); // // Summary: // This method is an implementation of System.Web.Mvc.IActionFilter.OnActionExecuted(System.Web.Mvc.ActionExecutedContext) // and supports the ASP.NET MVC infrastructure. It is not intended to be used // directly from your code. // // Parameters: // filterContext: // The filter context. public override void OnActionExecuted(ActionExecutedContext filterContext); // // Summary: // This method is an implementation of System.Web.Mvc.IActionFilter.OnActionExecuting(System.Web.Mvc.ActionExecutingContext) // and supports the ASP.NET MVC infrastructure. It is not intended to be used // directly from your code. // // Parameters: // filterContext: // The filter context. public override void OnActionExecuting(ActionExecutingContext filterContext); // // Summary: // This method is an implementation of System.Web.Mvc.IExceptionFilter.OnException(System.Web.Mvc.ExceptionContext) // and supports the ASP.NET MVC infrastructure. It is not intended to be used // directly from your code. // // Parameters: // filterContext: // The filter context. public void OnException(ExceptionContext filterContext); // // Summary: // This method is an implementation of System.Web.Mvc.IResultFilter.OnResultExecuted(System.Web.Mvc.ResultExecutedContext) // and supports the ASP.NET MVC infrastructure. It is not intended to be used // directly from your code. // // Parameters: // filterContext: // The filter context. public override void OnResultExecuted(ResultExecutedContext filterContext); // // Summary: // Called before the action result executes. // // Parameters: // filterContext: // The filter context, which encapsulates information for using System.Web.Mvc.AuthorizeAttribute. // // Exceptions: // System.ArgumentNullException: // The filterContext parameter is null. public override void OnResultExecuting(ResultExecutingContext filterContext); } }
常用屬性:
(1) AllowMultiple:獲取或設置一個值,該值指示是否可指定篩選器特性的多個實例。
(2) CacheProfile:緩存使用的配置文件的緩存名稱,可選屬性,默認值為空字符("")。
注意:包含在用戶控件(.ascx 文件)中的 @ OutputCache 指令不支持此屬性。在頁中指定此屬性時,屬性值必須與 outputCacheSettings 節下面的 outputCacheProfiles 元素中的一個可用項的名稱匹配。如果此名稱與配置文件項不匹配,將引發異常。
如果每個頁面的緩存時間相同,則不需要每個頁面設置,而是通過統一一個地方控制,這樣就可以更好的統一控制所有頁面的緩存時間。如果想改變緩存時間,只需要改一下web.config的配置信息即可,而不用每個頁面去修改。
(3) ChildActionCache:獲取或設置子操作緩存。
(4) Duration:緩存時間,以秒為單位,這個除非你的Location=None,可以不添加此屬性,其余時候都是必須的。
(5) OutputCacheLocation:枚舉類型,緩存的位置。當設置成None時,所有緩存將失效,默認為Any。
[1] Any:頁面被緩存在瀏覽器、代理服務器端和web服務器端;
[2] Client:緩存在瀏覽器;
[3] DownStream:頁面被緩存在瀏覽器和任何的代理服務器端;
[4] Server:頁面被緩存在Web服務器端;
[5] None:頁面不緩存;
[6] ServerAndClient:頁面被緩存在瀏覽器和web服務器端;
(6) VaryByContentEncoding:獲取或設置基於內容變化的編碼。一般設置為Accept-Encoding里面可能的Encoding名稱。
(7) VaryByCustom:獲取或設置基於自定義項變化的值。一個完全可以定制的設置,例如我們可能需要根據用戶角色來決定不同的緩存版本,或者根據瀏覽器的一些小版本號來區分不同的緩存版本,我們可以這樣設置:VaryByCustom=”Role,BrowserVersion”,這些名稱是自己定義的,光這樣寫當然是沒有用的,我們還需要在Global.asax文件中,添加一個特殊的方法,來針對這種特殊的需求進行處理。
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Routing; using System.Web.Security; namespace MvcApplicationCacheSample { // Note: For instructions on enabling IIS6 or IIS7 classic mode, // visit http://go.microsoft.com/?LinkId=9394801 public class MvcApplication : System.Web.HttpApplication { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); } public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults ); } protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); } public override string GetVaryByCustomString(HttpContext context, string custom) { switch(custom) { case "Role": { return string.Join(",", Roles.GetRolesForUser()); } case "BrowserVersion": { return context.Request.Browser.Type; } default: break; } return string.Empty; } } }
(8) VaryByHeader:獲取或設置基於標頭變化的值。可以根據用戶請求中所提供的一些Header信息不同而決定是否讀取緩存。
例如根據不同的語言,我們顯然是有不同的版本的。或者根據用戶瀏覽器不同,也可以緩存不同的版本。可以通過這樣設置:
VaryByHeader=”Accept-Language,User-Agent”
(9) VaryByParam:用於多個輸出緩存的字符串列表,並以“分號”進行分隔。默認時,該字符串與GET方法傳遞的參數或與POST方法傳遞的變量相對應。當被設置為多個參數時,輸出緩存將會為每個參數都准備一個與之相對應的文檔版本。可能值包括none,*,以及任何有效的查詢串或POST參數名稱。如果不想要為不同的已緩存內容指定參數,可以將其設置為none。如果想要指定所有的已緩存內容參數,可以設置為*。
<%@ OutputCache Duration="#ofseconds" Location="Any | Client | Downstream | Server | None | ServerAndClient " Shared="True | False" VaryByControl="controlname" VaryByCustom="browser | customstring" VaryByHeader="headers" VaryByParam="parametername" VaryByContentEncoding="encodings" CacheProfile="cache profile name | ''" NoStore="true | false" SqlDependency="database/table name pair | CommandNotification" %>
六、緩存依賴
SqlDependency:一個值,用於標識操作的輸出緩存所依賴的一組數據庫名稱和表名稱對。SqlCacheDependency 類在所有受支持的 SQL Server 版本 (7.0, 2000, 2005) 上監視特定的 SQL Server 數據庫表,數據庫表發生更改時,將自動刪除緩存項,並向 Cache 中添加新版本的項。
下面為應用實例。示例說明:數據庫為本地數據庫,庫名:wcfDemo,監聽表名:user。緩存時間為:3600秒即一小時。數據庫依賴周期為500毫秒,即每0.5秒監聽下數據庫是否有變化,如果有變化則立即更新緩存。
1、建立Control,測試代碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace MvcCache.Control.Controllers { public class SqlDependencyController : Controller { [OutputCache(CacheProfile = "SqlDependencyCache")] public ActionResult Index() { ViewBag.CurrentTime = System.DateTime.Now; return View(); } } }
2、在配置文件中配置CacheProfile為SqlDependencyCache的節,並且配置緩存對數據庫的依賴。
<?xml version="1.0" encoding="utf-8"?> <!-- For more information on how to configure your ASP.NET application, please visit http://go.microsoft.com/fwlink/?LinkId=169433 --> <configuration> <!--數據庫連接字符串--> <connectionStrings> <add name="Conn" connectionString="server=localhost;database=wcfDemo;uid=sa;pwd=123456;" providerName="System.Data.SqlClient"/> </connectionStrings> <!--數據庫連接字符串--> <appSettings> <add key="webpages:Version" value="2.0.0.0" /> <add key="webpages:Enabled" value="false" /> <add key="PreserveLoginUrl" value="true" /> <add key="ClientValidationEnabled" value="true" /> <add key="UnobtrusiveJavaScriptEnabled" value="true" /> </appSettings> <system.web> <!--配置緩存--> <caching> <!--緩存的數據庫依賴節--> <sqlCacheDependency> <databases> <add name="UserCacheDependency" connectionStringName="Conn" pollTime="500"/><!--Conn:數據庫連接字符串的名稱,name隨便啟名,緩存節會用到--> </databases> </sqlCacheDependency> <!--緩存的數據庫依賴節--> <outputCacheSettings> <outputCacheProfiles> <add name="SqlDependencyCache" duration="3600" sqlDependency="UserCacheDependency:user"/><!--UserCacheDependency:數據庫依賴配置節的名稱,user:數據庫中需要監聽的表名稱--> </outputCacheProfiles> </outputCacheSettings> </caching> <!--配置緩存--> <httpRuntime targetFramework="4.5" /> <compilation debug="true" targetFramework="4.5" /> <pages> <namespaces> <add namespace="System.Web.Helpers" /> <add namespace="System.Web.Mvc" /> <add namespace="System.Web.Mvc.Ajax" /> <add namespace="System.Web.Mvc.Html" /> <add namespace="System.Web.Routing" /> <add namespace="System.Web.WebPages" /> </namespaces> </pages> </system.web> <system.webServer> <validation validateIntegratedModeConfiguration="false" /> <handlers> <remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" /> <remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" /> <remove name="ExtensionlessUrlHandler-Integrated-4.0" /> <add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="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" /> <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" /> <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" /> </handlers> </system.webServer> </configuration>
注意:
(1) 由於是緩存對數據庫的依賴,應用時必須包含connectionStrings的節點。
(2) <add name="UserCacheDependency" connectionStringName="Conn" pollTime="500"/>。
[1] connectionStringName:數據庫連接字符串的名稱;
[2] pollTime:監聽數據庫變化的周期,以毫秒為單位。即每500毫秒查看下數據庫是否有變化。
(3) <add name="SqlDependencyCache" duration="3600" sqlDependency="UserCacheDependency:user"/>
[1] sqlDependency:數據依賴的節的名稱+冒號+數據表名稱(小寫)。如果這個依賴會用到多個表,則用“分號”間隔開,示例如下:UserCacheDependency:user;UserCacheDependency:user1
3、啟用該數據庫表的緩存依賴通知功能
打開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:表名稱(小寫)
因為只是監聽是否發生數據變化,因此表結構隨意,下面的我的表結構:
4、測試程序
上面的例子只打印了當前時間,如果不加入緩存依賴的情況下,1小時之內都應該運行出的結果都是同一個時間,每次Ctrl+F5強制刷新瀏覽器時不發生任務變化。當加入緩存依賴后,只要對數據庫的數據進行任意修改都會更新緩存的時間,即更改數據后再刷新瀏覽器時會看到時間在變化。
七、Response類的Cache屬性
用於獲取頁面緩存策略。該方式的核心是調用System.Web.HttpCachePolicy。該類主要包含用於設置緩存特定的HTTP標頭的方法和用於控制ASP.NET頁面輸出緩存的方法。與.NET Framework 1.x中的HttpCachePolicy類相比,.NET Framework 2.0中的HttpCachePolicy類得到了擴充和發展。主要是增加了一些重要方法,例如,SetOmitVarStar方法等。由於HttpCachePolicy類方法眾多,下面簡要說明幾個常用方法。
SetExpires方法:用於設置緩存過期的絕對時間。它的參數是一個DataTime類的實例,表示過期的絕對時間。
protectedvoid Page_Load(object sender, EventArgs e) { // 通過API設置緩存 //相當於@OutputCache指令中的Duration屬性 Response.Cache.SetExpires(DateTime.Now.AddSeconds(60)); Response.Cache.SetExpires(DateTime.Parse("6:00:00PM")); }
如上代碼,第一行代碼表示輸出緩存時間是60秒,並且頁面不隨任何GET或POST參數改變,等同於“<%@ OutputCache Duration="60" VaryByParam="none" %>”。第二行代碼設置緩存過期的絕對時間是當日下午6時整。
SetLastModified方法:用於設置頁面的Last-Modified HTTP標頭。Last-Modified HTTP標頭表示頁面上次修改時間,緩存將依靠它來進行計時。如果違反了緩存限制層次結構,此方法將失敗。該方法的參數是一個DataTime類的實例。
SetSlidingExpiration方法:該方法將緩存過期從絕對時間設置為可調時間。其參數是一個布爾值。當參數為true時,Cache-Control HTTP標頭將隨每個響應而更新。此過期模式與相對於當前時間將過期標頭添加到所有輸出集的IIS配置選項相同。當參數為False時,將保留該設置,且任何啟用可調整過期的嘗試都將靜態失敗。此方法不直接映射到HTTP標頭。它由后續模塊或輔助請求來設置源服務器緩存策略。
SetOmitVaryStar方法:ASP.NET 2.0新增的方法。用於指定在按參數進行區分時,響應是否應該包含vary:*標頭。方法參數是一個布爾值,若要指示HttpCachePolicy不對其VaryByHeaders屬性使用*值,則為true;否則為false。
SetCacheability方法:用於設置頁面的Cache-Control HTTP標頭。該標頭用於控制在網絡上緩存文檔的方式。該方法有兩種重載方式,所不同的是參數。一種重載方法的參數是HttpCacheability枚舉值,包括NoCache、Private、Public、Server、ServerAndNoCache和ServerAndPrivate(有關這些枚舉值的定義,可參考MSDN)。另一種方法的參數有兩個,一個參數是HttpCacheability枚舉值,另一個參數是字符串,表示添加到標頭的緩存控制擴展。需要注意的是,僅當與Private或NoCache指令一起使用時,字段擴展名才有效。如果組合不兼容的指令和擴展,則此方法將引發無效參數異常。