在ASP.NET页面后台代码类(code-behind class),我们可以使用Page类的Cache属性来访问data cache ,就像我们在第2步里的表达式:Cache["key"] = value一样;而在体系结构的类(注:具体到本文,就是缓存层类(ProductsCL),我们可以通过2种方式来访问:HttpRuntime.Cache 或 HttpContext.Current.Cache ;在Peter Johnson的博客里有一篇文章《HttpRuntime.Cache vs. HttpContext.Current.Cache》(),探讨了HttpRuntim与相对于HttpContext.Current的优点;在此,我们的ProductsCL类将使用HttpRuntime.
注意:如果你是使用的类库工程(Class Library projects),一定要记得引用System.Web才能使用HttpRuntime 和 HttpContext类。
如果没有在内存找到数据,ProductsCL类将从业务逻辑层BLL获取数据,并使用AddCacheItem(key, value)对数据进行缓存,可以用下面的代码向内存添加缓存数据,其缓存时间为60秒:
const double CacheDuration = 60.0; private void AddCacheItem(string rawKey, object value) { HttpRuntime.Cache.Insert(GetCacheKey(rawKey), value, null, DateTime.Now.AddSeconds(CacheDuration), Caching.Cache.NoSlidingExpiration); }
其中,DateTime.Now.AddSeconds(CacheDuration)指定了缓存时间—60秒;而 System.Web.Caching.Cache.NoSlidingExpiration指明了不存在可变缓存时间(no sliding expiration).虽然Insert()方法可以包含绝对时间和可变时间(absolute and sliding expiry)2种定义缓存时间的输入参数,但是你只能指定其中一个,如果你同时指定绝对时间和可变时间2个参数的话,Insert()方法会抛出一ArgumentException 异常。
注意:直接执行AddCacheItem(key, value)方法会有一些弊端,我们将在第4步解释并修正。
第4步:当数据被修改时使缓存失效
除了数据检索方法外,缓存层还应该包含插入、更新、删除数据的方法。缓存层的数据修改方法并不是修改缓存的数据,而是调用业务逻辑层的相应方法,然后使缓存数据失效。就像前面章节探讨的那样,当激活ObjectDataSource的缓存属性时,便可调用它的Insert, Update或Delete方法。
下面的UpdateProduct方法,说明了如何在缓存层CL执行数据修改方法:
[System.ComponentModel.DataObjectMethodAttribute(DataObjectMethodType.Update, false)] public bool UpdateProduct(string productName, decimal? unitPrice, int productID) { bool result = API.UpdateProduct(productName, unitPrice, productID); // TODO: Invalidate the cache return result; }
在业务逻辑层的方法返回数据以前,我们需要将缓存的数据失效。不过,这并非易事,无论ProductsCL class's GetProducts()还是GetProductsByCategoryID(categoryID)都会向内存添加条目,并且GetProductsByCategoryID(categoryID)方法会为每种类别添加几个条目(因为每种类别有几种甚至更多的产品)。
要使缓存数据失效,我们需要将ProductsCL类添加的所有条目删除。为此,在AddCacheItem(key, value)方法里,当添加条目时为其指定一个缓存从属体(cache dependency)。一般来说,缓存从属体可以是内存里的另一个条目;文件系统里的一个文件;又或者是Microsoft SQLServer database数据库里的数据。当从属体发生改变,或者从内存里移除时,其对应的缓存条目会自动的从内存删除。在本教程,当ProductsCL类向内存添加条目时,我们创建一个额外的条目作为其从属体。由此,要删除缓存条目,仅仅移除这些从属体即可。
我们来更改AddCacheItem(key, value)方法,当用该方法向内存添加缓存数据时,使每个条目与一个从属体(cache dependency)对应起来。
private void AddCacheItem(string rawKey, object value) { System.Web.Caching.Cache DataCache = HttpRuntime.Cache; // Make sure MasterCacheKeyArray[0] is in the cache - if not, add it if (DataCache[MasterCacheKeyArray[0]] == null) DataCache[MasterCacheKeyArray[0]] = DateTime.Now; // Add a CacheDependency System.Web.Caching.CacheDependency dependency = new CacheDependency(null, MasterCacheKeyArray); DataCache.Insert(GetCacheKey(rawKey), value, dependency, DateTime.Now.AddSeconds(CacheDuration), System.Web.Caching.Cache.NoSlidingExpiration); }
MasterCacheKeyArray是一个字符串数组,用来存储“ProductsCache”. 首先检查MasterCacheKeyArray,如果其为null,用当前date和time对其赋值。然后,创建一个从属体。CacheDependency类的构造器(constructor)可以有很多重载(overloads),本文使用的重载接受2个字符串数组作为输入参数。第一个参数指定文件作为从属体,但本文我们不大算用文件来做从属体,所以我们将第一个输入参数设为null;第二个参数指定cache keys作为从属体,本文我们指定为MasterCacheKeyArray。然后将该CacheDependency传递给Insert方法。
对AddCacheItem(key, value)方法做了上述修改后,要使缓存失效,很简单,将从属体移除即可: