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清空缓存时遇到问题详细分析,为了让大家更好地解决此类问题,希望本文对大家的学习有所帮助。