ASP.NET清空缓存时遇到的问题简析
在网站中要做一个清理缓存的功能(也就是在缓存为到期之前就强制缓存过期),程序中有的地方使用的HttpRuntime.Cache来做的缓存,而和数据库交互部分则使用ObjectDataSource提供的缓存机制。清理HttpRuntime.Cache的缓存很简单,只要
List<string>keys=newList<string>(); //retrieveapplicationCacheenumerator IDictionaryEnumeratorenumerator=HttpRuntime.Cache.GetEnumerator(); //copyallkeysthatcurrentlyexistinCache while(enumerator.MoveNext()) { keys.Add(enumerator.Key.ToString()); } //deleteeverykeyfromcache for(inti=0;i<keys.Count;i++) { HttpRuntime.Cache.Remove(keys[i]); }
就可以了。
本以为ObjectDataSource等数据源的缓存也是保存在HttpRuntime.Cache中,经过测试没想到竟然不是,因为执行上面的代码以后ObjectDataSource仍然是从缓存读取数据。
使用Reflector反编译发现ObjectDataSource是使用HttpRuntime.CacheInternal来实现的缓存。CacheInternal是internal的,因此没法直接写代码调用,同时CacheInternal中也没提供清空缓存的方法,只能通过实验发现_caches._entries是保存缓存的Hashtable,因此就用反射的方法调用CacheInternal,然后拿到_caches._entries,最后clear才算ok。
最终代码如下:
//HttpRuntime下的CacheInternal属性(Internal的,内存中是CacheMulti类型)是 ObjectDataSource等DataSource保存缓存的管理器 //因为CacheInternal、_caches、_entries等都是internal或者private的, 所以只能通过反射调用,而且可能会随着.Net升级而失效 objectcacheIntern=CommonHelper.GetPropertyValue(typeof(HttpRuntime),"CacheInternal")asIEnumerable; //_caches是CacheMulti中保存多CacheSingle的一个IEnumerable字段。 IEnumerable_caches=CommonHelper.GetFieldValue(cacheIntern,"_caches")asIEnumerable; foreach(objectcacheSinglein_caches) { ClearCacheInternal(cacheSingle); } privatestaticvoidClearCacheInternal(objectcacheSingle) { //_entries是cacheSingle中保存缓存数据的一个privateHashtable Hashtable_entries=CommonHelper.GetFieldValue(cacheSingle,"_entries")asHashtable; _entries.Clear(); } mary> ///得到type类型的静态属性propertyName的值 ///</summary> ///<paramname="type"></param> ///<paramname="propertyName"></param> ///<returns></returns> publicstaticobjectGetPropertyValue(Typetype,stringpropertyName) { foreach(PropertyInforInfointype.GetProperties (BindingFlags.NonPublic|BindingFlags.Static|BindingFlags.Public|BindingFlags.Instance)) { if(rInfo.Name==propertyName) { returnrInfo.GetValue(null,newobject[0]); } } thrownewException("无法找到属性:"+propertyName); } ///<summary> ///得到object对象的propertyName属性的值 ///</summary> ///<paramname="obj"></param> ///<paramname="propertyName"></param> ///<returns></returns> publicstaticobjectGetPropertyValue(objectobj,stringpropertyName) { Typetype=obj.GetType(); foreach(PropertyInforInfointype.GetProperties (BindingFlags.NonPublic|BindingFlags.Static|BindingFlags.Public|BindingFlags.Instance)) { if(rInfo.Name==propertyName) { returnrInfo.GetValue(obj,newobject[0]); } } thrownewException("无法找到属性:"+propertyName); } publicstaticobjectGetFieldValue(objectobj,stringfieldName) { Typetype=obj.GetType(); foreach(FieldInforInfointype.GetFields (BindingFlags.NonPublic|BindingFlags.Static|BindingFlags.Public|BindingFlags.Instance)) { if(rInfo.Name==fieldName) { returnrInfo.GetValue(obj); } } thrownewException("无法找到字段:"+fieldName); }
上面方法由于是通过crack的方法进行调用,可能有潜在的问题,因此仅供参考。
在google上搜索到另外一篇文章,主干是代码,代码的思路和我一样,贴过来也供参考。
privatevoidclearOutputCache() { Typect=this.Cache.GetType(); FieldInfocif=ct.GetField("_cacheInternal",BindingFlags.NonPublic|BindingFlags.Instance); Typecmt=Cache.GetType().Assembly.GetType("System.Web.Caching.CacheMultiple"); TypecachekeyType=Cache.GetType().Assembly.GetType("System.Web.Caching.CacheKey"); FieldInfocachesfield=cmt.GetField("_caches",BindingFlags.NonPublic|BindingFlags.Instance); objectcacheInternal=cif.GetValue(this.Cache); objectcaches=cachesfield.GetValue(cacheInternal); TypearrayType=typeof(Array); MethodInfoarrayGetter=arrayType.GetMethod("GetValue",newType[]{typeof(int)}); objectcacheSingle=arrayGetter.Invoke(caches,newobject[]{1}); FieldInfoentriesField=cacheSingle.GetType().GetField("_entries",BindingFlags.Instance|BindingFlags.NonPublic); Hashtableentries=(Hashtable)entriesField.GetValue(cacheSingle); List<object>keys=newList<object>(); foreach(objectoinentries.Keys) { keys.Add(o); } MethodInforemove=cacheInternal.GetType().GetMethod("Remove",BindingFlags.NonPublic|BindingFlags.Instance,null, newType[]{cachekeyType,typeof(CacheItemRemovedReason)},null); foreach(objectkeyinkeys) { remove.Invoke(cacheInternal,newobject[]{key,CacheItemRemovedReason.Removed}); } }
以上就是对ASP.NET清空缓存时遇到问题详细分析,为了让大家更好地解决此类问题,希望本文对大家的学习有所帮助。