ASP. NET Brief analysis of problems encountered when emptying cache

  • 2021-07-07 06:56:35
  • OfStack

In the website to do a clean cache function (that is, before the cache expires, force the cache to expire), some places in the program use HttpRuntime. Cache to do the cache, and the database interaction part uses the cache mechanism provided by ObjectDataSource. Cleaning the cache of HttpRuntime. Cache is simple, as long as


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]); 
   } 

Just do it.

I thought that the cache of data sources such as ObjectDataSource was also saved in HttpRuntime. Cache, but after testing, I didn't expect it to be, because ObjectDataSource still reads data from the cache after executing the above code.

Decompilation using Reflector reveals that ObjectDataSource is a cache implemented using HttpRuntime. CacheInternal. CacheInternal belongs to internal, so it can't be called by writing code directly. At the same time, CacheInternal doesn't provide a method to empty the cache. It can only be found through experiments that _ caches._entries is Hashtable for saving the cache, so CacheInternal is called by reflection method, and then _ caches._entries is obtained. Finally, clear is considered as ok.

The final code is as follows:


//HttpRuntime Under CacheInternal Attributes ( Internal Of, in memory is CacheMulti Type) is 
ObjectDataSource Etc DataSource Manager that saves the cache  
// Because CacheInternal , _caches , _entries And so on internal Or private Of, 
 So it can only be called through reflection, and it may be called with the .Net Upgrade and fail  
 object cacheIntern = CommonHelper.GetPropertyValue(typeof(HttpRuntime), "CacheInternal") as IEnumerable; 
 //_caches Yes CacheMulti Save more in CacheSingle Adj. 1 A IEnumerable Field.  
 IEnumerable _caches = CommonHelper.GetFieldValue(cacheIntern, "_caches") as IEnumerable; 
 foreach (object cacheSingle in _caches) 
 { 
  ClearCacheInternal(cacheSingle); 
 } 
 
private static void ClearCacheInternal(object cacheSingle) 
{ 
 //_entries Yes cacheSingle Object that holds cached data in the 1 A private Hashtable 
 Hashtable _entries = CommonHelper.GetFieldValue(cacheSingle, "_entries") as Hashtable; 
 _entries.Clear(); 
} 
 
mary> 
///  Get type Static properties of type propertyName Value of  
/// </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(" Unable to find property: " + propertyName); 
} 
 
/// <summary> 
///  Get object Object's propertyName The value of the property  
/// </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(" Unable to find property: " + 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(" Unable to find field: " + fieldName); 
} 

Because the above method is called through crack method, there may be potential problems, so it is for reference only.

In google search to another article, the backbone is the code, code ideas and I 1, paste over also for reference.


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 } ); 
 } 
}

The above is a detailed analysis of the problems encountered when ASP. NET empties the cache. In order to solve such problems better, I hope this article is helpful for everyone's study.


Related articles: