解析ASP.NET缓存清空遇到的问题

2010-09-10 14:16:55来源:作者:

在网站中要做一个清理缓存的功能(也就是在缓存为到期之前就强制缓存过期),程序中有的地方使用的HttpRuntime.Cache来做的缓存,而和数据库交互部分则使用ObjectDataSource提供的缓存机制。清理HttpRuntime.Cache的缓

在网站中要做一个清理缓存的功能(也就是在缓存为到期之前就强制缓存过期),程序中有的地方使用的HttpRuntime.Cache来做的缓存,而和数据库交互部分则使用ObjectDataSource提供的缓存机制。清理HttpRuntime.Cache的缓存很简单,只要如下写就可以了。
 

C# Code复制内容到剪贴板
  1. List<string> keys = new List<string>();               
  2. // retrieve application Cache enumerator  IDictionaryEnumerator enumerator = HttpRuntime.Cache.GetEnumerator();               
  3. // copy all keys that currently exist in Cache               
  4. while (enumerator.MoveNext())              {                   
  5.   keys.Add(enumerator.Key.ToString());   
  6.              }       
  7.           // delete every key from cache           
  8.       for (int i = 0; i < keys.Count; i++)         
  9.         {                  HttpRuntime.Cache.Remove(keys[i]);             
  10.    }   

  本以为ObjectDataSource等数据源的缓存也是保存在HttpRuntime.Cache中,经过测试没想到竟然不是,因为执行上面的代码以后ObjectDataSource仍然是从缓存读取数据。

  使用Reflector反编译发现ObjectDataSource是使用HttpRuntime.CacheInternal来实现的缓存,气氛呀,为什么微软总爱搞“特殊化”,对外提供一个Cache用,自己偷偷用CacheInternal做缓存。CacheInternal是internal 的,因此没法直接写代码调用,同时CacheInternal中也没提供清空缓存的方法,只能通过实验发现_caches._entries是保存缓存的 Hashtable,因此就用反射的方法调用CacheInternal,然后拿到_caches._entries,最后clear才算ok。

  最终代码如下:

C# Code复制内容到剪贴板
  1. //HttpRuntime下的CacheInternal属性(Internal的,内存中是CacheMulti类型)是ObjectDataSource等DataSource保存缓存的管理器     
  2. //因为CacheInternal、_caches、_entries等都是internal或者private的,所以只能通过反射调用,而且可能会随着.Net升级而失效       
  3.   object cacheIntern = CommonHelper.GetPropertyValue(typeof(HttpRuntime), "CacheInternal"as IEnumerable;         
  4. //_caches是CacheMulti中保存多CacheSingle的一个IEnumerable字段。       
  5. IEnumerable _caches = CommonHelper.GetFieldValue(cacheIntern, "_caches"as IEnumerable;      foreach (object cacheSingle in _caches)      {         
  6.    ClearCacheInternal(cacheSingle);   
  7.      }     
  8. private static void ClearCacheInternal(object cacheSingle)     
  9. {         
  10. //_entries是cacheSingle中保存缓存数据的一个private Hashtable     
  11. Hashtable _entries = CommonHelper.GetFieldValue(cacheSingle, "_entries"as Hashtable;   
  12.      _entries.Clear();   
  13. }   mary>   
  14. /// 得到type类型的静态属性propertyName的值     
  15. /// </summary>   
  16. /// <param name="type">   
  17. </param>     
  18. /// <param name="propertyName">   
  19. </param>     
  20. ///   
  21. <returns>   
  22. </returns>   
  23. public static object GetPropertyValue(Type type, string propertyName)   
  24.   {       
  25.   foreach (PropertyInfo rInfo in type.GetProperties(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Public | BindingFlags.Instance))     
  26.    {           
  27.   if (rInfo.Name == propertyName)          {               
  28. return rInfo.GetValue(nullnew object[0]);           
  29.   }       
  30.   }       
  31. throw new Exception("无法找到属性:" + propertyName);   
  32. }     
  33. /// <summary>   
  34.   /// 得到object对象的propertyName属性的值   
  35. /// </summary>   
  36. /// <param name="obj">   
  37. </param>     
  38. /// <param name="propertyName">   
  39. </param>   
  40. /// <returns>   
  41. </returns>   
  42. public static object GetPropertyValue(object obj, string propertyName)     
  43. {         
  44. Type type = obj.GetType();     
  45.     foreach (PropertyInfo rInfo in type.GetProperties(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Public | BindingFlags.Instance))   
  46.      {           
  47.   if (rInfo.Name == propertyName)          {               
  48. return rInfo.GetValue(obj, new object[0]);           
  49. }       
  50. }     
  51.     throw new Exception("无法找到属性:" + propertyName);     
  52. }     
  53. public static object GetFieldValue(object obj, string fieldName)   
  54.   {       
  55.   Type type = obj.GetType();     
  56.    foreach (FieldInfo rInfo in type.GetFields(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Public | BindingFlags.Instance))   
  57.       {           
  58.   if (rInfo.Name == fieldName)          {               
  59.   return rInfo.GetValue(obj);     
  60.        }     
  61.    }       
  62. throw new Exception("无法找到字段:" + fieldName);   
  63. }   

  上面方法由于是通过crack的方法进行调用,可能有潜在的问题,因此仅供参考。

  在google上搜索到另外一篇文章 http://www.msdnkk.hu/Articles/Clear_OutputCache-Minden_oldal_torlese ,由于是匈牙利文的,也看不懂在说什么,不过主干是代码,看他代码的思路和我一样,贴过来也供参考

C# Code复制内容到剪贴板
  1. private void clearOutputCache()   
  2.   {      Type ct = this.Cache.GetType();   
  3.      FieldInfo cif = ct.GetField( "_cacheInternal", BindingFlags.NonPublic | BindingFlags.Instance );     
  4.     Type cmt = Cache.GetType().Assembly.GetType( "System.Web.Caching.CacheMultiple" );   
  5.      Type cachekeyType = Cache.GetType().Assembly.GetType( "System.Web.Caching.CacheKey" );   
  6.      FieldInfo cachesfield = cmt.GetField( "_caches", BindingFlags.NonPublic | BindingFlags.Instance );   
  7.       object cacheInternal = cif.GetValue( this.Cache );   
  8.      object caches = cachesfield.GetValue( cacheInternal );     
  9.      Type arrayType = typeof( Array );   
  10.       MethodInfo arrayGetter = arrayType.GetMethod( "GetValue"new Type[] { typeofint ) } );   
  11.      object cacheSingle = arrayGetter.Invoke( caches, new object[] { 1 } );   
  12.       FieldInfo entriesField = cacheSingle.GetType().GetField( "_entries", BindingFlags.Instance | BindingFlags.NonPublic );     
  13.    Hashtable entries = (Hashtable) entriesField.GetValue( cacheSingle );   
  14.       List<object> keys = new List<object>();       
  15.   foreachobject o in entries.Keys )      {           
  16. keys.Add( o );   
  17.      }       
  18.    MethodInfo remove = cacheInternal.GetType().GetMethod( "Remove", BindingFlags.NonPublic | BindingFlags.Instance, null,          new Type[] { cachekeyType, typeof( CacheItemRemovedReason )   
  19. }, null );     
  20.    foreachobject key in keys )     
  21.     {         
  22.    remove.Invoke( cacheInternal, new object[] { key, CacheItemRemovedReason.Removed   
  23. }   
  24. );     
  25.   
  26.    }   
  27. }   
关键词:ASP.NET

赞助商链接: