2009-06-09 13 views
16

Qualcuno può spiegare perché non è possibile inserire un oggetto nullo nella cache di ASP.NET?ASP.NET non può memorizzare nella cache il valore nullo

string exampleItem = null; 

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

Il messaggio di errore di eccezione indica che l'oggetto "valore" non può essere nullo. Nella mia applicazione ci sono validi motivi per cui vorremmo memorizzare un valore nullo nella cache.

risposta

17

Il valore sottostante Cache è Hashtable o Dictionary<string, object>, i cui getter non distinguono tra nessun valore su quella chiave o un valore nullo su quella chiave.

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

consideri un segnaposto elemento utilizzando "null", simile a DbNull.Value.

+1

dizionario * non * distinguere tra (Questo è tutto fuori dalla parte superiore della mia testa, quindi mi scuso per eventuali errori di battitura stupide.) null e nessun valore. Ottenere il valore per una chiave che non esiste genera una KeyNotFoundException e la memorizzazione di un valore nullo è valida. –

+1

Ah. Ho provato solo Hashtable. Un po 'più di prova che Cache è basata su Hashtable, con un controllo pre-inserimento. –

+0

In ritardo alla festa, ma solo per informazione, sembra che MemoryCache comunichi una chiave mancante restituendo 'null'. Quindi se permette di inserire valori nulli, non conoscerà la differenza tra i due. – GettnDer

11

Per chiarire un po 'la risposta accettata di Michael Petrotta (troppo lungo per un commento, temo), le concrete implementazioni di CacheInternal (CacheSingle e CacheMultiple, l'ultima delle quali gestisce semplicemente più istanze del primo), che è ciò che viene utilizzato internamente dal tipo di cache pubblica per supportare i metodi Get, Add, Insert, ecc., si basa su un HashTable per l'archiviazione. Tuttavia, non c'è mai alcuna domanda se esiste o meno un valore per una chiave particolare nella HashTable, perché i valori nativi (memorizzati nella cache) non sono memorizzati direttamente in HashTable. Invece, la HashTable è piena di oggetti CacheEntry unici che racchiudono le chiavi ei valori memorizzati nella cache (CacheEntry deriva in realtà da CacheKey, aggiungendo una proprietà Value basata su oggetti, tra le altre cose: il requisito di valore non nullo può essere trovato nel suo costruttore).

Sulla base della mia lettura del codice, non c'è alcun motivo tecnico evidente per gli autori di aver richiesto un CacheEntry.Value non null, tranne che l'oggetto Cache pubblico non espone un metodo di tipo Contains- o Exists, e naturalmente non espone gli oggetti interni di CacheEntry sottostanti, restituisce solo i valori di CacheEntry. Quindi, come per la risposta di Michael, senza forzare i valori ad essere non nulli, non è possibile per gli utenti di oggetti Cache sapere se esiste un particolare valore di chiave. È anche possibile, ma richiederebbe una maggiore lettura del codice per essere sicuri, che l'approccio piuttosto complesso adottato internamente per gestire le dipendenze degli oggetti memorizzati nella cache, le scadenze, gli eventi e gli aggiornamenti sul posto delle voci di HashTable si basino, in qualche modo, sui valori essere non nullo.

8

Come possibile alternativa o soluzione, è possibile archiviare invece un oggetto anziché il proprio valore. Per esempio (questo presuppone che il valore è una stringa, ma potrebbe essere generico)

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

...

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

In questo modo non si è mai inserendo nulla. Per ottenere il valore indietro, basta estrarlo dalla confezione:

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

+0

Questo funziona perfettamente con il mio meccanismo di caching esistente con poche modifiche grazie. – Paul

+1

Ho usato un modello simile ma ho appena usato una Tuple per il mio wrapper; In questo modo posso avere in cache più tipi di elementi come specificato e non devi preoccuparti del barfing dell'oggetto stesso sull'inserto nullo nella cache – Rostov

+0

Questa è una buona soluzione. Un'altra opzione decente è l'utilizzo di Null Object Pattern come descritto qui http://stackoverflow.com/a/9820884/1302581. – Robertas

Problemi correlati