2009-06-09 10 views
16

¿Alguien puede explicar por qué no puede insertar un objeto nulo en la memoria caché de ASP.NET?ASP.NET no puede almacenar en caché el valor nulo

string exampleItem = null; 

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

El mensaje de error de excepción indica que el objeto "valor" no puede ser nulo. En mi aplicación hay razones válidas por las que deseamos almacenar un valor nulo en la memoria caché.

Respuesta

17

es subyacente Cache probablemente un Hashtable o Dictionary<string, object>, cuya captadores no diferenciar entre ningún valor a esa clave o un valor nulo en esa clave.

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

Considere un elemento utilizando marcador de posición "nula", similar a DbNull.Value.

+1

Diccionario * no * diferenciar entre (esto es la parte superior de la cabeza, así que disculpas por errores tipográficos tontas.) nulo y sin valor Obtener el valor de una clave que no existe arroja una KeyNotFoundException, y el almacenamiento de un valor nulo es válido. –

+1

Ah. Solo probé Hashtable. Algo más de evidencia de que Cache está basado en Hashtable, con un chequeo previo a la inserción. –

+0

Tarde para la fiesta, pero solo para información, parece que MemoryCache comunica una clave perdida al devolver 'nulo'. Entonces, si permite insertar valores nulos, no sabrá la diferencia entre los dos. – GettnDer

11

Para aclarar la respuesta aceptada de Michael Petrotta un poco (demasiado tiempo para un comentario, me temo), las implementaciones concretas de CacheInternal (CacheSingle y CacheMultiple, el último de los cuales simplemente gestiona instancias múltiples de la anterior), que es lo que se utiliza internamente por el tipo de caché pública para admitir sus métodos Get, Add, Insert, etc., depende de una HashTable para el almacenamiento. Sin embargo, nunca hay dudas de si hay o no un valor para una clave en particular en la tabla Hash, ya que los valores nativos (en caché) no se almacenan en la tabla HashTable directamente. En cambio, el HashTable está lleno de objetos únicos CacheEntry que envuelven las claves y valores almacenados en caché (CacheEntry en realidad deriva de CacheKey, agregando una propiedad Value basada en Object, entre otras cosas, el requisito de valor no nulo se puede encontrar en su constructor).

Según mi lectura del código, no existe una razón técnica obvia para que los autores hayan requerido un CacheEntry.Value no nulo, excepto que el objeto Cache pública no expone un método de tipo Contiene o existe, y, por supuesto, no expone los objetos internos de CacheEntry, solo devuelve los valores de CacheEntry. Entonces, según la respuesta de Michael, sin obligar a los valores a ser no nulos, los usuarios de objetos de caché no pueden saber si existe un valor clave particular. También es posible, pero requeriría más lectura de código para estar seguro, que el enfoque bastante complejo tomado internamente para administrar dependencias de objetos en caché, vencimientos, eventos y actualizaciones in situ de entradas HashTable podría depender, de alguna manera, de los valores ser no nulo.

8

Como alternativa posible o alternativa, en su lugar puede almacenar un objeto en lugar de su valor. Por ejemplo (esto supone que su valor es una cadena, pero podría ser genérico)

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

...

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

De esa manera usted está insertando no nulo. Para obtener el valor de nuevo, que acaba de extraer de la envoltura:

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

+0

Esto funciona muy bien con mi mecanismo de caché existente con pequeñas modificaciones gracias. – Paul

+1

He usado un patrón similar pero acabo de usar un Tuple para mi envoltorio; de esa manera puedo tenerlo en la memoria caché de varios tipos de elementos como se especifica y no tengo que preocuparme de que el objeto mismo vomite en el inserto nulo en el caché – Rostov

+0

Esa es una buena solución. Otra opción decente es usar el Patrón de Objeto Nulo como se describe aquí http://stackoverflow.com/a/9820884/1302581. – Robertas

Cuestiones relacionadas