ASP.NET Caching - Dipendenze

ASP.NET supporta la cache dependencies; questa feature permette di relazionare un oggetto che abbiamo in cache con un'altra risorsa, in modo tale che, quando questa risorsa cambia, l'oggetto in cache verrà rimosso automaticamente.

Esistono tre tipi di dipendenza:

  • Con un'altro oggetto in cache
  • Con un file o una directory
  • Query su database

Per creare una dipendenza nella cache, bisognerà creare un oggetto CacheDependency ed usarlo quando inseriremo un oggetto in cache.

Per esempio, il codice seguente, creerà una dipendenza con un file XML.
Se il file verrà cambiato, cancellato o sovrascritto, l'oggetto in cache scadrà:

CacheDependency prodDependency = new CacheDependency(Server.MapPath("ProductList.xml"));
Cache.Insert("ProductInfo", prodInfo, prodDependency);

Se avessimo creato una dipendenza su una directory, l'oggetto CacheDependency avrebbe controllato se un file viene aggiunto, modificato, cancellato o se una sotto-directory viene rinominata, creata o rimossa.

I cambiamenti che occorranno un livello inferiore a quello della subdirectory (inserimento di un file in una subdirectory o la creazione di una subdirectory in una subdirectory), non verranno notificati.

 

L'oggetto CacheDependency creato, inizierà la sua fase di controllo immediatamente, senza attendere che venga associato ad un oggetto in cache.

Più Dipendenze

Potrebbe tornare necessario un oggetto CacheDependency che dipende da più risorse (la modifica di due files decreta l'invalidità dell'oggetto in cache).

In questo caso avremo bisogno di creare un oggetto AggregateCacheDependency:

CacheDependency dep1 = new CacheDependency(Server.MapPath("ProductList1.xml"));
CacheDependency dep2 = new CacheDependency(Server.MapPath("ProductList2.xml"));
                                                                               
CacheDependency[] deps = new CacheDependency[] { dep1, dep2 };                 
                                                                               
AggregateCacheDependency aggregateDep = new AggregateCacheDependency();        
aggregateDep.Add(deps);                                                        
Cache.Insert("ProductInfo", prodInfo, aggregateDep);                           

Questo è soltanto un esempio, in quanto l'oggetto CacheDependency può accettare un array di files.
AggregateCacheDependency torna utile nel caso in cui gli oggetti da controllare non sono solamente files.

Riferendoci al post Data Caching, in questi casi torna utile l'utilizzo del delegate onRemoveCallback. Tramite questo delegate potremmo controllare perchè l'oggetto è stato rimosso, se perchè una delle sue dipendenze è cambiata o se per qualche altro motivo.

ASP.NET mette a disposizione l'enum CacheItemRemovedReason per capire perchè il nostro oggetto è stato rimosso dalla cache.

ASP.NET Caching - Data Source Controls

SqlDataSource, ObjectDataSource e XmlDataSource supportano nativamente il caching.

Usare il caching con questi controlli è altamente consigliato, perchè ad ogni postback la sorgente dati viene richiesta.
In più i dati vengono richiesti per ogni controllo in bound, quindi se avremo 3 controlli in bound, ad ogni refresh, partiranno 3 query.

In questo caso mettendo in cache questi dati si ridurranno drasticamente i tempi di caricamento.

Questi controlli offrono un insieme di proprietà utili per attivare comodamente la cache:

  • EnableCaching: true per attivare il caching.
  • CacheExpirationPolicy: può essere di due tipi Absolute o Sliding (guardare i post precedenti per capire cosa si intende)
  • CacheDuration: Se la CacheExpirationPolicy è settata su Absolute, il controllo memorizzerà i dati in cache alla prima operazione e li mantiene in memoria per il periodo di tempo specificato, quindi viene cancellata e aggiornata all'operazione successiva.
    Se invece è impostata su Sliding i dati vengono memorizzati durante la prima operazione di recupero dati, e ripristina l'intervallo di tempo durante il quale i dati vengono mantenuti nella cache per ogni operazione successiva.
    La cache scadrà se non viene registrata alcuna attività per un periodo di tempo uguale al valore settato nella CacheDuration.
  • CacheKeyDependency - SqlCacheDependency: Permette di creare una dipendenza da un oggetto in cache ad un'altro (CacheKeyDependency) o con una tabella nel database (SqlCacheDependency).

SqlDataSource

    <asp:SqlDataSource ID="SqlDataSource1" runat="server" 
        ConnectionString="<%$ ConnectionStrings:AdventureWorksConnectionString %>" 
        EnableCaching="true"
        CacheDuration="600"
        CacheExpirationPolicy="Absolute"
        SelectCommand="SELECT * FROM Person.Contact">
        <SelectParameters>
            <asp:Parameter DefaultValue="1" Name="EmailPromotion" Type="Int32" />
        </SelectParameters>
    </asp:SqlDataSource>
        <asp:GridView ID="GridView1" runat="server" 
            DataSourceID="SqlDataSource1">
        </asp:GridView>

Per questo esempio ottengo tutti i dati dalla tabella Person.Contact del database AdventureWorks che potete trovare su CodePlex.

Test alla mano, ottenuti con Fiddler, la differenza tra i dati non copiati in cache e quelli copiati in cache è del 10% di tempo impiegato tra la request e il respond.

ObjectDataSource

L'ObjectDataSource è molto limitato, lavora solamente DataSet e/o DataTable.
Se utilizzato con un'altro tipo di oggetto riceveremo un NotSupportedException.

Se si vorranno copiare nell'ObjectDataSource cache oggetti diversi dai due sopra menzionati, bisognerà implementare anche i metodi di inserimento dei dati.