Inside ModelVirtualCasting #4: Come funziona CacheThis?

di Marco De Sanctis, in Architettura,

Quarto post della serie sugli internals dell'applicazione che abbiamo mostrato nel corso della Real Code Conference 4.0 lo scorso 25 Maggio 2010 i cui sorgenti sono disponibili su Codeplex:

  1. Introduzione ai repository
  2. Architettura interna dei repository
  3. La cache
  4. Come funziona CacheThis

Dell'attributo CacheThis ha già parlato un pochino Daniele nello scorso post, qualche giorno prima di RCC mi ha proposto di realizzare questa cosa perché era una figheria simpatica da far vedere, e allora mi sono convinto e l'ho messa su! Si tratta di un sistema per effettuare caching dei risultati di un metodo in maniera trasparente. Infatti, in maniera dichiarativa, ci basta scrivere:

public interface INewsRepository : IRepository<INewsRepository, News> 
{ 
    [CacheThis("last-news", 60)] 
    List<NewsDTO> GetLastNewsDTO(int number); 
}

ed ecco che, come per incanto, il risultato di GetLastNewsDTO viene prelevato dalla cache, se presente, oppure recuperato tramite una query su DataBase. Ma come funziona tutto questo, visto che, l'implementazione di questo metodo non ha la minima cognizione del concetto di Cache?

public List<NewsDTO> GetLastNewsDTO(int number) 
{ 
    return CurrentObjectSet.AsQueryable() 
        .OrderByDescending(n => n.PublicationDate) 
        .Take(number) 
        .SelectDTO<News, NewsDTO>().ToList(); 
}

CacheThis è un tipico esempio di Aspect Oriented Programming sul quale potremmo scrivere qualche decina di post ma che, in parole povere, consente di iniettare logica in maniera modulare nelle chiamate ai metodi di un oggetto, più o meno agendo in questo modo:

image

In pratica, possiamo fare in modo che Unity, quando chiediamo un'istanza di INewsRepository, non restituisca direttamente NewsRepository, come ci aspetteremmo, bensì un proxy, che implementa però la stessa interfaccia così che il nostro codice non si accorga minimamente che qualcuno sta cambiando le carte in tavola.

Cosa fa questo proxy? Beh, normalmente niente, si limita a girare ogni chiamata a NewsRepository e a restituire il risultato prodotto, tranne quando il metodo invocato sia decorato dal famigerato attributo CacheThis, nel qual caso viene eseguito il nostro bel CacheHandler che, grossomodo, è fatto così (in pseudocodice):

public Result Invoke(...) 
{ 
    if (Cache.Contains(key)) 
        return Cache[key]; 
     var result = invokeRealMethod(...);
     Cache.Add(key, result);
     return result; 
}
 

In parole povere, CacheHandler verifica se il risultato è già presente in cache, se viene trovato lo restituisce, altrimenti esegue il repository vero e proprio, mette in cache il risultato e lo ritorna.

Ora.. a dire il vero l'implementazione contenuta in ModelVC soffre di un paio di limitazioni, che sono nella lista della spesa delle feature da metter su per la prossima versione:

  • supporta esclusivamente l'invalidazione via timeout, mentre sarebbe bello se una Add/Modify/Delete di una news tramite repository invalidasse automaticamente la cache;
  • come sappiamo, quando realizziamo una query in LINQ to Entities, questa non viene eseguita finché non se ne esplori il risultato; morale della favola.. dobbiamo forzarne l'esecuzione all'interno di NewsRepository (concreto), ad esempio con un ToList, altrimenti rischiamo di mettere in cache l'expression tree e non i risultati veri e propri.

D'altro canto, però, CacheThis riesce a mantenere in Cache diversi risultati dello stesso metodo, creando chiavi on-the-fly a seconda dei parametri con cui è stato invocato e, soprattutto, ci mostra come in maniera semplice possiamo sfruttare questa tecnica (che di per sé è invece parecchio avanzata) per iniettare funzionalità tramite Unity all'interno del nostro codice.

Che dire? Se volete saperne di più... i sorgenti di ModelVC non aspettano altro che essere scaricati, e continuate a seguire questa serie di post che io e gli altri ragazzi dello staff continueremo a pubblicare nei prossimi giorni.

Ciauz!

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Nella stessa categoria
I più letti del mese