自定义缓存控件html
前面咱们介绍了经过查询参数实现缓存一个或多个页面,其实ASP.NET也容许咱们自定义缓存方式来决定是否缓存页或重用现有的,这时咱们能够经过设置VaryByCustom属性来实现。web
假设,如今咱们要设计基于不一样UserHostName的缓存,因为程序在执行过程当中,首先调用GetVaryByCustomString()方法来肯定是否缓存页面或重用现有的,因此咱们能够经过重写该方法实现基于UserHostName的缓存,具体实现以下:ajax
- /// <summary>
- /// Gets vary cache based on custom string value.
- /// </summary>
- /// <param name="context">Http context.</param>
- /// <param name="custom">custom string</param>
- /// <returns></returns>
- public override string GetVaryByCustomString(HttpContext context, string custom)
- {
- if (string.Equals(custom, "UserHostName", StringComparison.OrdinalIgnoreCase))
- {
- // Indicates that the cache should be vary on user host name.
- return Context.Request.UserHostName;
- }
- return base.GetVaryByCustomString(context, custom);
- }
前面咱们重写了GetVaryByCustomString()方法,使得UserHostName值不一样时,获取相应的缓存值。数据库
而后让程序基于UserHostName建立缓存,因此咱们要在页面添加如下代码:json
- <!-- set vary cache based on custom string value -->
- <%@ OutputCache Duration="30" VaryByParam="None" VaryByCustom="UserHostName" %>
咱们经过自定义如今GetVaryByCustomString()方法,实现了Web程序根据UserHostName实施不一样的缓存方式,其实,咱们还能够实现更多种类缓存方案,例如:基于用户角色、时间和Url等等。api
片断缓存缓存
在某些状况下,咱们不能缓存整个页面,但咱们仍想缓存部分页面从而减轻系统的负担;其实,咱们能够经过两种方法实现:片断缓存和数据缓存.安全
为了实现片断缓存,咱们须要建立自定义控件缓存部分页面,而后咱们把OutputCache指令添加到自定义控件中,这样整个页面将不会被缓存,而自定义缓存控件除外。app
前面咱们介绍了输出缓存的使用,只需在页面中添加OutputCache指令,假设咱们要在几个页面中添加输出缓存这可能比较简单,但咱们要在几十个页面中添加输出缓存功能,并且前面介绍的例子中Duration属性值都是直接Hard code到每一个页面中,若是咱们须要修改Duration属性值,那么就必须修改每一个页面了,ASP.NET还须要从新编译这些页面,这不利于咱们的维护,最重要的是增长了咱们的工做量。dom
其实,咱们能够在web.config文件中定义一个outputCacheProfile(ProductCacheProfile),而后在页面中添加CacheProfile属性而且赋值为ProductCacheProfile,web.config文件设置以下:
- <caching>
- <!-- Sets out put cache profile-->
- <outputCacheSettings>
- <outputCacheProfiles>
- <add name="ProductCacheProfile" duration="30"/>
- </outputCacheProfiles>
- </outputCacheSettings>
- </caching>
如今,咱们在页面中添加CacheProfile属性,而且设置为ProductCacheProfile,以下所示:
- <!-- set CacheProfile property -->
- <%@ OutputCache CacheProfile="ProductCacheProfile" VaryByParam="None" %>
数据缓存
Cache对象是线程安全:这表示无需显式实现锁定或解锁,在添删Cache对象中的元素,然而,在Cache对象中元素必须是线程安全的。例如,咱们建立一个实体Product,并且存在多个客户端可能同时操做该对象的状况,这时咱们必须为实体Product实现锁定和解锁操做(同步操做请参考《单例模式(Singleton)的6种实现》)。
Cache对象中的缓存项自动移除:当缓存过时,依赖项被修改或内存不足缓存ASP.NET会自动移除该缓存项。
缓存项支持依赖关系:咱们能够给缓存项添加文件、数据库表或其余资源类型的依赖关系。
SqlDataSource缓存
当咱们在SqlDataSource控件中启用缓存,它缓存SelectCommand中的结果;若是SQL查询语句中带有参数时,SqlDataSource控件会缓存每个参数值对应的结果。
这跟咱们以前经过输出缓存实现报表程序缓存查询页面效果同样,因此咱们将使用SqlDataSource缓存实现该效果。
假设咱们要提供一个报表程序,让用户经过选择产品名称(ProductName),获取相应的产品信息。
首先,咱们在页面中建立两个数据源控件:sourceProductName和sourceProduct,接着把数据源分别绑定到Dropdownlist和Gridview中,具体实现以下:
- <!-- The product number datasource START -->
- <asp:SqlDataSource ID="sourceProductName" runat="server" ProviderName="System.Data.SqlClient"
- EnableCaching="True" CacheDuration="3600" ConnectionString="<%$ ConnectionStrings:SQLCONN %>"
- SelectCommand="SELECT ProductNumber FROM Production.Product"></asp:SqlDataSource>
- <!-- The product number datasource END -->
- <!-- The product datasource START -->
- <asp:SqlDataSource ID="sourceProduct" runat="server" ProviderName="System.Data.SqlClient"
- EnableCaching="True" CacheDuration="3600" ConnectionString="<%$ ConnectionStrings:SQLCONN %>"
- SelectCommand="SELECT Name, ProductNumber, SafetyStockLevel, ReorderPoint, StandardCost, DaysToManufacture
- FROM Production.Product WHERE ProductNumber=@ProductNumber">
- <SelectParameters>
- <asp:ControlParameter ControlID="ddlProductNumber" Name="ProductNumber" PropertyName="SelectedValue" />
- </SelectParameters>
- </asp:SqlDataSource>
- <!-- The product number datasource END -->
- <!-- Binding the product number to gridview control -->
- <!-- NOTE: Due to search and result in the same page, so need to set AutoPostBack is True-->
- <asp:DropDownList ID="ddlProductNumber" AutoPostBack="True" DataSourceID="sourceProductName"
- DataTextField="ProductNumber" runat="server">
- </asp:DropDownList>
- <!-- Binding the product datasource to gridview control -->
- <asp:GridView ID="gvProduct" runat="server" DataSourceID="sourceProduct" CssClass="Product">
- </asp:GridView>
如今咱们对报表程序进行查询,若是ProudctName以前没有被缓存起来就会建立相应的缓存,而已经缓存起来的将被重用,查询结果以下:
缓存的依赖关系
缓存项之间的依赖
ASP.NET Cache容许咱们创建缓存之间的依赖关系,即一个缓存项依赖于另外一个缓存项;如下示例代码建立了二个缓存项,而且它们之间创建依赖关系。具体实现以下:
- // Creates cache object Key1.
- Cache["Key1"] = "Cache Item 1";
- // Makes Cache["Key2"] dependent on Cache["Key1"].
- string[] dependencyKey = new string[1];
- dependencyKey[0] = "Key1";
- // Creates a CacheDependency object.
- CacheDependency dependency = new CacheDependency(null, dependencyKey);
- // Establishs dependency between cache Key1 and Key2.
- Cache.Insert("Key2", "Cache Item 2", dependency);
如今,当Key1缓存项更新或从缓存中删除,Key2缓存项就会自动从缓存删除。
文件依赖
前面咱们介绍了缓存项之间的依赖关系,ASP.NET Cache还提供缓存项与文件之间的依赖关系,当文件被更新或删除对应的缓存项也将失效。
在上篇博文《Ajax与JSON的一些总结》的最后介绍的一个DEMO——Weibo Feed中,咱们经过实时方式向新浪微博API发送请求获取相应的数据,但在必定时间内请求的次数是有限制的,一旦超出了限制次数就再也不接受请求了(具体请参考Rate-limiting)。因此能够经过Cache的方式把数据缓存起来,当客户端请求时,若是缓存数据已经存在那么直接返回数据,不然从新想微博API请求数据。
首先,咱们建立一个HttpHandler,它负责向微博API发送请求而且把数据保存的文件中,最后把数据返回的客户端。
接下来,咱们定义CacheData()方法把微博数据保存到文本文件中而且创建缓存与数据文件的依赖关系。
- /// <summary>
- /// Caches the data into text file.
- /// </summary>
- /// <param name="context">The http context</param>
- private void CacheData(HttpContext context)
- {
- // Weibo API.
- string uri = context.Request.QueryString["api"] + "?" +
- "source=" + context.Request.QueryString["source"] + "&" +
- "count=" + context.Request.QueryString["count"];
- HttpWebResponse response = this.GetWeibos(uri);
- if (null == response)
- {
- throw new ArgumentNullException("Response is null");
- }
- string jsonData;
- // Writes the reponse data into text file.
- using (var reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding(response.CharacterSet)))
- {
- jsonData = reader.ReadToEnd();
- }
- string dataPath = context.Server.MapPath("weibo.json");
- using (var writer = new StreamWriter(dataPath, false, Encoding.GetEncoding(response.CharacterSet)))
- {
- writer.Write(jsonData);
- }
- // Establishs dependency between cache weibo and text file.
- // Sets cache expires after 2 minuntes.
- HttpRuntime.Cache.Insert("weibo", jsonData, Dep, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(2));
- }
如今咱们把数据保存到文本文件中而且创建了缓存weibo与数据文件的依赖关系,接下来咱们要把JSON格式数据返回给客户端。
- /// <summary>
- /// Responses the weibo data.
- /// </summary>
- /// <param name="context">The http contex.</param>
- private void ResponseWeibo(HttpContext context)
- {
- // Gets the weibo cache data.
- byte[] buf = Encoding.UTF8.GetBytes(HttpRuntime.Cache["weibo"].ToString());
- // Writes the data into output stream.
- context.Response.OutputStream.Write(buf, 0, buf.Length);
- context.Response.OutputStream.Flush();
- ////context.Response.Close();
- }
上面咱们把JSON格式字符串转换为Byte数值,而后写入到OutputStream中,最后把数据返回给客户端。
- // The function to get weibo data.
- loadWeibo: function() {
- $.ajax({
- // Weibo API.
- url: "WeiboHandler.ashx",
- type: "GET",
- // NOTE: We get the data from same domain,
- // dataType is json.
- dataType: "json",
- data: {
- source: JQWeibo.appKey,
- count: JQWeibo.numWeibo
- },
- // When the requet completed, then invokes success function.
- success: function(data, textStatus, xhr) {
- // Sets html structure.
- var html =
- '<div class="weibo">' +
- '<a href="http://weibo.com/DOMAIN" target="_blank">USER</a>' +
- ':WEIBO_TEXT<div class="time">AGO</div>';
- // Appends weibos into html page.
- for (var i = 0; i < data.length; i++) {
- $(JQWeibo.appendTo).append(
- html.replace('WEIBO_TEXT', JQWeibo.ify.clean(data[i].text))
- // Uses regex and declare DOMAIN as global, if found replace all.
- .replace(/DOMAIN/g, data[i].user.domain)
- .replace(/USER/g, data[i].user.screen_name)
- .replace('AGO', JQWeibo.timeAgo(data[i].created_at))
- );
- }
- }
- })
- }
总结缓存可使应用程序的性能获得很大的提升,所以在设计应用程序应该予以考虑,本博文主要介绍了ASP.NET中输出缓存和数据缓存的应用场合和区别。
页面缓存适用于生成的页面一般都相同或改变时间比较固定状况,例如:数据在每小时都会更新,那么咱们能够设置duration为3600s。
数据缓存适用生成的页面老是在变化状况。
http://www.codeproject.com/Articles/29899/Exploring-Caching-in-ASP-NET
http://msdn.microsoft.com/zh-cn/library/aa478965.aspx#XSLTsection129121120120
http://www.amazon.com/Beginning-ASP-NET-3-5-2008-Professional/dp/1590598911
原文连接:http://www.cnblogs.com/rush/archive/2012/06/30/2571438.html