views:

707

answers:

3

Can anyone explain why you cannot insert a null object into the ASP.NET cache?

string exampleItem = null;

HttpRuntime.Cache.Insert("EXAMPLE_KEY", 
                        exampleItem, 
                        Nothing,                           
                        DateTime.Now.AddHours(1),
                        System.Web.Caching.Cache.NoSlidingExpiration);

The exception error message states that the "value" object cannot be null. In my application there are valid reasons why we whould want to store a null value in the cache.

+3  A: 

Underlying Cache is likely a Hashtable or Dictionary<string, object>, whose getters do not differentiate between no value at that key, or a null value at that key.

Hashtable table = new Hashtable();
object x = table["foo"];
table.Add("foo", null);
object y = table["foo"];
Console.WriteLine(x == y); // prints 'True'

Consider a using placeholder "null" item, similar to DbNull.Value.

Michael Petrotta
Dictionary<T,K> *does* differentiate between null and no value. Getting the value for a key that doesn't exist throws a KeyNotFoundException, and storing a null value is valid.
Jonathan
Ah. I only tested Hashtable. Somewhat more evidence that Cache is based on Hashtable, with a pre-insert check.
Michael Petrotta
+3  A: 

To clarify Michael Petrotta's accepted answer a bit (too long for a comment, I'm afraid), the concrete implementations of CacheInternal (CacheSingle and CacheMultiple, the latter of which merely manages multiple instances of the former), which is what's utilized internally by the public Cache type to support its Get, Add, Insert, etc. methods, do rely on a HashTable for storage. However, there's never any question of whether there is or isn't a value for a particular key in the HashTable, because the native (cached) values aren't stored in the HashTable directly. Instead, the HashTable is filled with unique CacheEntry objects that wrap the cached keys and values (CacheEntry actually derives from CacheKey, adding an Object-based Value property, among other things; the non-null value requirement can be found in its constructor).

Based on my reading of the code, there's no obvious technical reason for the authors to have required a non-null CacheEntry.Value, except that the public Cache object doesn't expose a Contains- or Exists-type method, and of course doesn't expose the internal underlying CacheEntry objects, it only returns the CacheEntry values. So, as per Michael's answer, without forcing values to be non-null it isn't possible for Cache object users to know whether a particular key value exists. It's also possible, but would require more code reading to know for sure, that the rather complex approach taken internally to manage cached object dependencies, expirations, events, and in-place updates of HashTable entries might rely, in some way, on the values being non-null.

ewbi
A: 

You should .remove the item from the cache if exampleItem is null rather than trying to store a null into the cache.

string exampleItem = null;

if (exampleItem == null)
  HttpRuntime.Cache.Remove("EXAMPLE_KEY");
else
  HttpRuntime.Cache.Insert("EXAMPLE_KEY", 
                        exampleItem, 
                        Nothing,                           
                        DateTime.Now.AddHours(1),
                        System.Web.Caching.Cache.NoSlidingExpiration);
Jeff Robinson