ASP.NET清空缓存时遇到的问题简析
程序员文章站
2023-12-19 14:15:04
在网站中要做一个清理缓存的功能(也就是在缓存为到期之前就强制缓存过期),程序中有的地方使用的httpruntime.cache来做的缓存,而和数据库交互部分则使用objec...
在网站中要做一个清理缓存的功能(也就是在缓存为到期之前就强制缓存过期),程序中有的地方使用的httpruntime.cache来做的缓存,而和数据库交互部分则使用objectdatasource提供的缓存机制。清理httpruntime.cache的缓存很简单,只要
list<string> keys = new list<string>(); // retrieve application cache enumerator idictionaryenumerator enumerator = httpruntime.cache.getenumerator(); // copy all keys that currently exist in cache while (enumerator.movenext()) { keys.add(enumerator.key.tostring()); } // delete every key from cache for (int i = 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升级而失效 object cacheintern = commonhelper.getpropertyvalue(typeof(httpruntime), "cacheinternal") as ienumerable; //_caches是cachemulti中保存多cachesingle的一个ienumerable字段。 ienumerable _caches = commonhelper.getfieldvalue(cacheintern, "_caches") as ienumerable; foreach (object cachesingle in _caches) { clearcacheinternal(cachesingle); } private static void clearcacheinternal(object cachesingle) { //_entries是cachesingle中保存缓存数据的一个private hashtable hashtable _entries = commonhelper.getfieldvalue(cachesingle, "_entries") as hashtable; _entries.clear(); } mary> /// 得到type类型的静态属性propertyname的值 /// </summary> /// <param name="type"></param> /// <param name="propertyname"></param> /// <returns></returns> public static object getpropertyvalue(type type, string propertyname) { foreach (propertyinfo rinfo in type.getproperties (bindingflags.nonpublic | bindingflags.static | bindingflags.public | bindingflags.instance)) { if (rinfo.name == propertyname) { return rinfo.getvalue(null, new object[0]); } } throw new exception("无法找到属性:" + propertyname); } /// <summary> /// 得到object对象的propertyname属性的值 /// </summary> /// <param name="obj"></param> /// <param name="propertyname"></param> /// <returns></returns> public static object getpropertyvalue(object obj, string propertyname) { type type = obj.gettype(); foreach (propertyinfo rinfo in type.getproperties (bindingflags.nonpublic | bindingflags.static | bindingflags.public | bindingflags.instance)) { if (rinfo.name == propertyname) { return rinfo.getvalue(obj, new object[0]); } } throw new exception("无法找到属性:" + propertyname); } public static object getfieldvalue(object obj, string fieldname) { type type = obj.gettype(); foreach (fieldinfo rinfo in type.getfields (bindingflags.nonpublic | bindingflags.static | bindingflags.public | bindingflags.instance)) { if (rinfo.name == fieldname) { return rinfo.getvalue(obj); } } throw new exception("无法找到字段:" + fieldname); }
上面方法由于是通过crack的方法进行调用,可能有潜在的问题,因此仅供参考。
在google上搜索到另外一篇文章,主干是代码,代码的思路和我一样,贴过来也供参考。
private void clearoutputcache() { type ct = this.cache.gettype(); fieldinfo cif = ct.getfield( "_cacheinternal", bindingflags.nonpublic | bindingflags.instance ); type cmt = cache.gettype().assembly.gettype( "system.web.caching.cachemultiple" ); type cachekeytype = cache.gettype().assembly.gettype( "system.web.caching.cachekey" ); fieldinfo cachesfield = cmt.getfield( "_caches", bindingflags.nonpublic | bindingflags.instance ); object cacheinternal = cif.getvalue( this.cache ); object caches = cachesfield.getvalue( cacheinternal ); type arraytype = typeof( array ); methodinfo arraygetter = arraytype.getmethod( "getvalue", new type[] { typeof( int ) } ); object cachesingle = arraygetter.invoke( caches, new object[] { 1 } ); fieldinfo entriesfield = cachesingle.gettype().getfield( "_entries", bindingflags.instance | bindingflags.nonpublic ); hashtable entries = (hashtable) entriesfield.getvalue( cachesingle ); list<object> keys = new list<object>(); foreach( object o in entries.keys ) { keys.add( o ); } methodinfo remove = cacheinternal.gettype().getmethod( "remove", bindingflags.nonpublic | bindingflags.instance, null, new type[] { cachekeytype, typeof( cacheitemremovedreason ) }, null ); foreach( object key in keys ) { remove.invoke( cacheinternal, new object[] { key, cacheitemremovedreason.removed } ); } }
以上就是对asp.net清空缓存时遇到问题详细分析,为了让大家更好地解决此类问题,希望本文对大家的学习有所帮助。