解析ASP.NET緩存清空遇到的問題

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

在網(wǎng)站中要做一個(gè)清理緩存的功能(也就是在緩存為到期之前就強(qiáng)制緩存過期),程序中有的地方使用的HttpRuntime.Cache來做的緩存,而和數(shù)據(jù)庫(kù)交互部分則使用ObjectDataSource提供的緩存機(jī)制。清理HttpRuntime.Cache的緩

在網(wǎng)站中要做一個(gè)清理緩存的功能(也就是在緩存為到期之前就強(qiáng)制緩存過期),程序中有的地方使用的HttpRuntime.Cache來做的緩存,而和數(shù)據(jù)庫(kù)交互部分則使用ObjectDataSource提供的緩存機(jī)制。清理HttpRuntime.Cache的緩存很簡(jiǎn)單,只要如下寫就可以了。
 

C# Code復(fù)制內(nèi)容到剪貼板
  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等數(shù)據(jù)源的緩存也是保存在HttpRuntime.Cache中,經(jīng)過測(cè)試沒想到竟然不是,因?yàn)閳?zhí)行上面的代碼以后ObjectDataSource仍然是從緩存讀取數(shù)據(jù)。

  使用Reflector反編譯發(fā)現(xiàn)ObjectDataSource是使用HttpRuntime.CacheInternal來實(shí)現(xiàn)的緩存,氣氛呀,為什么微軟總愛搞“特殊化”,對(duì)外提供一個(gè)Cache用,自己偷偷用CacheInternal做緩存。CacheInternal是internal 的,因此沒法直接寫代碼調(diào)用,同時(shí)CacheInternal中也沒提供清空緩存的方法,只能通過實(shí)驗(yàn)發(fā)現(xiàn)_caches._entries是保存緩存的 Hashtable,因此就用反射的方法調(diào)用CacheInternal,然后拿到_caches._entries,最后clear才算ok。

  最終代碼如下:

C# Code復(fù)制內(nèi)容到剪貼板
  1. //HttpRuntime下的CacheInternal屬性(Internal的,內(nèi)存中是CacheMulti類型)是ObjectDataSource等DataSource保存緩存的管理器     
  2. //因?yàn)镃acheInternal、_caches、_entries等都是internal或者private的,所以只能通過反射調(diào)用,而且可能會(huì)隨著.Net升級(jí)而失效       
  3.   object cacheIntern = CommonHelper.GetPropertyValue(typeof(HttpRuntime), "CacheInternal"as IEnumerable;         
  4. //_caches是CacheMulti中保存多CacheSingle的一個(gè)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中保存緩存數(shù)據(jù)的一個(gè)private Hashtable     
  11. Hashtable _entries = CommonHelper.GetFieldValue(cacheSingle, "_entries"as Hashtable;   
  12.      _entries.Clear();   
  13. }   mary>   
  14. /// 得到type類型的靜態(tài)屬性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對(duì)象的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的方法進(jìn)行調(diào)用,可能有潛在的問題,因此僅供參考。

  在google上搜索到另外一篇文章 http://www.msdnkk.hu/Articles/Clear_OutputCache-Minden_oldal_torlese ,由于是匈牙利文的,也看不懂在說什么,不過主干是代碼,看他代碼的思路和我一樣,貼過來也供參考

C# Code復(fù)制內(nèi)容到剪貼板
  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. }   
關(guān)鍵詞:ASP.NET

贊助商鏈接: