ASP.NET can't cache null value
Asked Answered
S

3

23

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.

Stitching answered 9/6, 2009 at 2:26 Comment(0)
A
21

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.

Anus answered 9/6, 2009 at 2:30 Comment(3)
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.Entablature
Ah. I only tested Hashtable. Somewhat more evidence that Cache is based on Hashtable, with a pre-insert check.Anus
Late to the party, but just for information, it seems that the MemoryCache communicates a missing key by returning 'null'. So if it allows inserting null values, it will not know the difference between the two.Aqueous
A
16

As a possible alternative or work-around, you can instead store an object rather than your value. For instance (this assumes your value is a string, but it could be generic)

public class CacheItemWrapper
{
    public string Value { get; set; }
}

...

cache.Insert(cacheKey, new CacheItemWrapper { Value = null }, ...);

That way you are never inserting null. To get the value back, you just extract it from the wrapper:

var val = cache.Get(cacheKey);
if (val != null) return val.Value;

(This is all off the top of my head, so apologies for any silly typos.)

Aam answered 3/1, 2013 at 14:53 Comment(3)
This works great with my existing caching mechanism with little modification thanks.Timothee
I've used a similar pattern but just used a Tuple<T> for my wrapper; that way I can have it cache multiple types of items as specified and don't have to worry about the object itself barfing on the null insert into the cacheJablonski
That's a nice workaround. Another decent option is using Null Object Pattern as described here https://mcmap.net/q/584876/-null-as-value-in-httpruntime-cache-add.Osteotomy
B
12

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.

Bullington answered 9/6, 2009 at 4:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.