Memorizzazione di dati nella cache all'avvio dell'applicazione (C#)

di Scott Mitchell

Scarica il PDF

In qualsiasi applicazione Web alcuni dati verranno usati frequentemente e alcuni dati verranno usati raramente. È possibile migliorare le prestazioni dell'applicazione ASP.NET caricando in anticipo i dati usati di frequente, una tecnica nota come Memorizzazione nella cache. Questa esercitazione illustra un approccio al caricamento proattivo, che consiste nel caricare i dati nella cache all'avvio dell'applicazione.

Introduzione

Le due esercitazioni precedenti hanno esaminato i dati di memorizzazione nella cache nei livelli di presentazione e memorizzazione nella cache. Nella memorizzazione nella cache dei dati con ObjectDataSource è stato esaminato l'uso delle funzionalità di memorizzazione nella cache di ObjectDataSource per memorizzare nella cache i dati nel livello presentazione. Memorizzazione nella cache dei dati nell'architettura esaminata nella memorizzazione nella cache in un nuovo livello di memorizzazione nella cache separato. Entrambe queste esercitazioni hanno usato il caricamento reattivo durante l'uso della cache dei dati. Con il caricamento reattivo, ogni volta che i dati vengono richiesti, il sistema controlla prima di tutto se si trova nella cache. In caso contrario, recupera i dati dall'origine di origine, ad esempio il database e lo archivia nella cache. Il vantaggio principale per il caricamento reattivo è la sua facilità di implementazione. Uno dei suoi svantaggi è la sua prestazioni irregolare tra le richieste. Si supponga di usare il livello di memorizzazione nella cache dall'esercitazione precedente per visualizzare le informazioni sul prodotto. Quando questa pagina viene visitata per la prima volta o visitata per la prima volta dopo che i dati memorizzati nella cache sono stati rimossi a causa di vincoli di memoria o della scadenza specificata, i dati devono essere recuperati dal database. Pertanto, queste richieste di utenti richiedono più tempo rispetto alle richieste degli utenti che possono essere gestite dalla cache.

Il caricamento proattivo fornisce una strategia di gestione della cache alternativa che semplifica le prestazioni tra le richieste caricando i dati memorizzati nella cache prima che sia necessario. In genere, il caricamento proattivo usa un processo che controlla periodicamente o riceve una notifica quando è stato eseguito un aggiornamento ai dati sottostanti. Questo processo aggiorna quindi la cache per mantenerla aggiornata. Il caricamento proattivo è particolarmente utile se i dati sottostanti provengono da una connessione di database lenta, un servizio Web o un'altra origine dati particolarmente lenta. Tuttavia, questo approccio al caricamento proattivo è più difficile da implementare, poiché richiede la creazione, la gestione e la distribuzione di un processo per verificare le modifiche e aggiornare la cache.

Un altro sapore del caricamento proattivo e il tipo che verrà esplorato in questa esercitazione sta caricando i dati nella cache all'avvio dell'applicazione. Questo approccio è particolarmente utile per la memorizzazione nella cache dei dati statici, ad esempio i record nelle tabelle di ricerca del database.

Nota

Per un'analisi più approfondita delle differenze tra il caricamento proattivo e reattivo, nonché gli elenchi di pro, cons e raccomandazioni sull'implementazione, fare riferimento alla sezione Gestione del contenuto di una cache della Guida all'architettura di memorizzazione nella cache per le applicazioni .NET Framework.

Passaggio 1: Determinazione dei dati da memorizzare nella cache all'avvio dell'applicazione

Gli esempi di memorizzazione nella cache usando il caricamento reattivo esaminato nelle due esercitazioni precedenti funzionano bene con i dati che possono cambiare periodicamente e non richiedono molto tempo per generare. Tuttavia, se i dati memorizzati nella cache non cambiano mai, la scadenza utilizzata dal caricamento reattivo è superflua. Analogamente, se i dati memorizzati nella cache richiedono molto tempo per generare, gli utenti i cui richieste trovano la cache vuota dovranno sopportare un'attesa prolungata mentre i dati sottostanti vengono recuperati. Prendere in considerazione la memorizzazione nella cache di dati statici e dati che richiedono un tempo eccezionale per generare all'avvio dell'applicazione.

Anche se i database hanno molti valori dinamici, che cambiano di frequente, la maggior parte ha anche una quantità equa di dati statici. Ad esempio, tutti i modelli di dati hanno una o più colonne che contengono un determinato valore da un set fisso di scelte. Una Patients tabella di database potrebbe avere una PrimaryLanguage colonna, il cui set di valori potrebbe essere inglese, spagnolo, francese, russo, giapponese e così via. Spesso, questi tipi di colonne vengono implementati usando le tabelle di ricerca. Anziché archiviare la stringa inglese o francese nella Patients tabella, viene creata una seconda tabella con due colonne, un identificatore univoco e una descrizione stringa, con un record per ogni valore possibile. La PrimaryLanguage colonna nella Patients tabella archivia l'identificatore univoco corrispondente nella tabella di ricerca. Nella figura 1, la lingua primaria di John Doe è inglese, mentre Ed Johnson è russo.

La tabella Lingue è una tabella di ricerca usata dalla tabella pazienti

Figura 1: La Languages tabella è una tabella di ricerca usata dalla Patients tabella

L'interfaccia utente per la modifica o la creazione di un nuovo paziente includerebbe un elenco a discesa di lingue consentite popolate dai record nella Languages tabella. Senza memorizzazione nella cache, ogni volta che questa interfaccia viene visitata, il sistema deve eseguire query sulla Languages tabella. Questo è sprecato e non necessario poiché i valori della tabella di ricerca cambiano molto raramente, se mai.

È possibile memorizzare nella cache i Languages dati usando le stesse tecniche di caricamento reattive esaminate nelle esercitazioni precedenti. Il caricamento reattivo, tuttavia, usa una scadenza basata su tempo, che non è necessaria per i dati di tabella di ricerca statici. Mentre la memorizzazione nella cache usando il caricamento reattivo sarebbe migliore di nessuna memorizzazione nella cache, l'approccio migliore sarebbe quello di caricare in modo proattivo i dati della tabella di ricerca nella cache all'avvio dell'applicazione.

In questa esercitazione verrà illustrato come memorizzare nella cache i dati della tabella di ricerca e altre informazioni statiche.

Passaggio 2: Analisi dei diversi modi per memorizzare nella cache i dati

Le informazioni possono essere memorizzate nella cache a livello di codice in un'applicazione ASP.NET usando un'ampia gamma di approcci. È già stato illustrato come usare la cache dei dati nelle esercitazioni precedenti. In alternativa, gli oggetti possono essere memorizzati nella cache a livello di codice usando membri statici o stato dell'applicazione.

Quando si lavora con una classe, in genere è necessario creare un'istanza della classe prima che i membri possano essere accessibili. Ad esempio, per richiamare un metodo da una delle classi nel livello della logica di business, è necessario creare prima un'istanza della classe:

ProductsBLL productsAPI = new ProductsBLL();
productsAPI.SomeMethod();
productsAPI.SomeProperty = "Hello, World!";

Prima di poter richiamare SomeMethod o usare SomeProperty, è necessario prima creare un'istanza della classe usando la new parola chiave. AlcuniMethod e SomeProperty sono associati a una determinata istanza. La durata di questi membri è associata alla durata dell'oggetto associato. I membri statici, d'altra parte, sono variabili, proprietà e metodi condivisi tra tutte le istanze della classe e, di conseguenza, hanno una durata fino a quando la classe. I membri statici vengono denotati dalla parola chiave static.

Oltre ai membri statici, i dati possono essere memorizzati nella cache usando lo stato dell'applicazione. Ogni applicazione ASP.NET gestisce una raccolta nome/valore condivisa tra tutti gli utenti e le pagine dell'applicazione. Questa raccolta può essere accessibile usando la HttpContextproprietà della classe e usata dalla classe code-behind di Applicationuna pagina di ASP.NET, ad esempio:

Application["key"] = value;
object value = Application["key"];

La cache dei dati offre un'API molto più ricca per la memorizzazione nella cache dei dati, fornendo meccanismi per le scadenze basate su tempo e dipendenze, priorità dell'elemento della cache e così via. Con membri statici e stato dell'applicazione, tali funzionalità devono essere aggiunte manualmente dallo sviluppatore di pagine. Quando si memorizzano nella cache i dati all'avvio dell'applicazione per la durata dell'applicazione, tuttavia, i vantaggi della cache dei dati sono moot. In questa esercitazione verrà esaminato il codice che usa tutte e tre le tecniche per la memorizzazione nella cache dei dati statici.

Passaggio 3: Memorizzazione nella cache dei dati dellaSupplierstabella

Le tabelle di database Northwind implementate in data non includono tabelle di ricerca tradizionali. Le quattro tabelle DataTable implementate in DAL tutte le tabelle modello i cui valori non sono statici. Anziché dedicare il tempo per aggiungere una nuova tabella dati al dal e quindi a una nuova classe e ai metodi BLL, per questa esercitazione si pretende solo che i Suppliers dati della tabella siano statici. Pertanto, è possibile memorizzare nella cache questi dati all'avvio dell'applicazione.

Per iniziare, creare una nuova classe denominata StaticCache.cs nella CL cartella.

Creare la classe StaticCache.cs nella cartella CL

Figura 2: Creare la StaticCache.cs classe nella CL cartella

È necessario aggiungere un metodo che carica i dati all'avvio nell'archivio cache appropriato, nonché metodi che restituiscono dati da questa cache.

[System.ComponentModel.DataObject]
public class StaticCache
{
    private static Northwind.SuppliersDataTable suppliers = null;
    public static void LoadStaticCache()
    {
        // Get suppliers - cache using a static member variable
        SuppliersBLL suppliersBLL = new SuppliersBLL();
        suppliers = suppliersBLL.GetSuppliers();
    }
    [DataObjectMethodAttribute(DataObjectMethodType.Select, true)]
    public static Northwind.SuppliersDataTable GetSuppliers()
    {
        return suppliers;
    }
}

Il codice precedente usa una variabile membro statica, , suppliersper contenere i risultati dal SuppliersBLL metodo della GetSuppliers() classe, che viene chiamato dal LoadStaticCache() metodo . Il LoadStaticCache() metodo deve essere chiamato durante l'avvio dell'applicazione. Dopo aver caricato questi dati all'avvio dell'applicazione, qualsiasi pagina che deve lavorare con i dati del fornitore può chiamare il StaticCache metodo della GetSuppliers() classe. Pertanto, la chiamata al database per ottenere i fornitori avviene una sola volta, all'avvio dell'applicazione.

Anziché usare una variabile membro statica come archivio cache, è possibile usare in alternativa lo stato dell'applicazione o la cache dei dati. Il codice seguente mostra la classe ritooled per usare lo stato dell'applicazione:

[System.ComponentModel.DataObject]
public class StaticCache
{
    public static void LoadStaticCache()
    {
        // Get suppliers - cache using application state
        SuppliersBLL suppliersBLL = new SuppliersBLL();
        HttpContext.Current.Application["key"] = suppliersBLL.GetSuppliers();
    }
    [DataObjectMethodAttribute(DataObjectMethodType.Select, true)]
    public static Northwind.SuppliersDataTable GetSuppliers()
    {
        return HttpContext.Current.Application["key"] as Northwind.SuppliersDataTable;
    }
}

In LoadStaticCache()le informazioni sul fornitore vengono archiviate nella chiave della variabile dell'applicazione. Viene restituito come tipo appropriato (Northwind.SuppliersDataTable) da GetSuppliers(). Mentre lo stato dell'applicazione può essere accessibile nelle classi code-behind di pagine di ASP.NET usando Application["key"], nell'architettura è necessario usare HttpContext.Current.Application["key"] per ottenere l'oggetto corrente HttpContext.

Analogamente, la cache dei dati può essere usata come archivio cache, come illustrato nel codice seguente:

[System.ComponentModel.DataObject]
public class StaticCache
{
    public static void LoadStaticCache()
    {
        // Get suppliers - cache using the data cache
        SuppliersBLL suppliersBLL = new SuppliersBLL();
        HttpRuntime.Cache.Insert(
          /* key */                "key", 
          /* value */              suppliers, 
          /* dependencies */       null, 
          /* absoluteExpiration */ Cache.NoAbsoluteExpiration, 
          /* slidingExpiration */  Cache.NoSlidingExpiration, 
          /* priority */           CacheItemPriority.NotRemovable, 
          /* onRemoveCallback */   null);
    }
    [DataObjectMethodAttribute(DataObjectMethodType.Select, true)]
    public static Northwind.SuppliersDataTable GetSuppliers()
    {
        return HttpRuntime.Cache["key"] as Northwind.SuppliersDataTable;
    }
}

Per aggiungere un elemento alla cache dei dati senza scadenza basata su tempo, usare i System.Web.Caching.Cache.NoAbsoluteExpiration valori e System.Web.Caching.Cache.NoSlidingExpiration come parametri di input. Questo particolare overload del metodo della Insert cache dati è stato selezionato in modo da poter specificare la priorità dell'elemento della cache. La priorità viene usata per determinare gli elementi da scavengere dalla cache quando la memoria disponibile è bassa. In questo caso viene usata la priorità NotRemovable, che garantisce che l'elemento della cache non venga scavendato.

Nota

Questo download di questa esercitazione implementa la classe usando l'approccio StaticCache della variabile membro statico. Il codice per le tecniche dello stato dell'applicazione e della cache dei dati è disponibile nei commenti nel file di classe.

Passaggio 4: Esecuzione del codice all'avvio dell'applicazione

Per eseguire il codice all'avvio di un'applicazione Web, è necessario creare un file speciale denominato Global.asax. Questo file può contenere gestori eventi per eventi a livello di applicazione, sessione e richiesta e qui è possibile aggiungere codice che verrà eseguito ogni volta che l'applicazione viene avviata.

Aggiungere il file alla directory radice dell'applicazione Web facendo clic con il Global.asax pulsante destro del mouse sul nome del progetto del sito Web nel Esplora soluzioni di Visual Studio e scegliendo Aggiungi nuovo elemento. Nella finestra di dialogo Aggiungi nuovo elemento selezionare il tipo di elemento Classe applicazione globale e quindi fare clic sul pulsante Aggiungi.

Nota

Se nel progetto è già presente un Global.asax file, il tipo di elemento Classe applicazione globale non verrà elencato nella finestra di dialogo Aggiungi nuovo elemento.

Aggiungere il file Global.asax alla directory radice dell'applicazione Web

Figura 3: Aggiungere il Global.asax file alla directory radice dell'applicazione Web (fare clic per visualizzare l'immagine a dimensione intera)

Il modello di file predefinito Global.asax include cinque metodi all'interno di un tag lato <script> server:

  • Application_Start viene eseguito al primo avvio dell'applicazione Web
  • Application_End viene eseguito quando l'applicazione viene arrestata
  • Application_Error viene eseguito ogni volta che un'eccezione non gestita raggiunge l'applicazione
  • Session_Start viene eseguito quando viene creata una nuova sessione
  • Session_End viene eseguito quando una sessione è scaduta o abbandonata

Il Application_Start gestore eventi viene chiamato una sola volta durante il ciclo di vita di un'applicazione. L'applicazione avvia la prima volta che viene richiesta una risorsa ASP.NET dall'applicazione e continua a essere eseguita fino al riavvio dell'applicazione, che può verificarsi modificando il contenuto della /Bin cartella, modificando , modificando Global.asaxil contenuto nella App_Code cartella o modificando il Web.config file, tra le altre cause. Per una discussione più dettagliata sul ciclo di vita dell'applicazione, vedere ASP.NET Panoramica del ciclo di vita dell'applicazione.

Per queste esercitazioni è sufficiente aggiungere codice al Application_Start metodo, quindi è possibile rimuovere gli altri. In Application_Startchiamare semplicemente il StaticCache metodo della LoadStaticCache() classe , che caricherà e memorizza nella cache le informazioni sul fornitore:

<%@ Application Language="C#" %>
<script runat="server">
    void Application_Start(object sender, EventArgs e) 
    {
        StaticCache.LoadStaticCache();
    }
</script>

Questo è tutto ciò che occorre fare. All'avvio dell'applicazione, il LoadStaticCache() metodo afferra le informazioni sul fornitore dal BLL e lo archivia in una variabile membro statica (o in qualsiasi archivio cache usato nella StaticCache classe ). Per verificare questo comportamento, impostare un punto di interruzione nel Application_Start metodo ed eseguire l'applicazione. Si noti che il punto di interruzione viene raggiunto all'avvio dell'applicazione. Le richieste successive, tuttavia, non causano l'esecuzione del Application_Start metodo.

Usare un punto di interruzione per verificare che sia in corso l'esecuzione del gestore eventi Application_Start

Figura 4: Usare un punto di interruzione per verificare che il Application_Start gestore eventi sia in esecuzione (fare clic per visualizzare l'immagine a dimensione intera)

Nota

Se non si raggiunge il punto di interruzione al primo avvio del Application_Start debug, è perché l'applicazione è già stata avviata. Forzare il riavvio dell'applicazione modificando i Global.asax file o Web.config e quindi riprovare. È sufficiente aggiungere (o rimuovere) una riga vuota alla fine di uno di questi file per riavviare rapidamente l'applicazione.

Passaggio 5: Visualizzazione dei dati memorizzati nella cache

A questo punto la StaticCache classe ha una versione dei dati del fornitore memorizzati nella cache all'avvio dell'applicazione a cui è possibile accedere tramite il relativo GetSuppliers() metodo. Per usare questi dati dal livello presentazione, è possibile usare ObjectDataSource o richiamare a livello di codice il StaticCache metodo della GetSuppliers() classe da una classe code-behind di una pagina ASP.NET. Si esaminerà ora l'uso dei controlli ObjectDataSource e GridView per visualizzare le informazioni sui fornitori memorizzate nella cache.

Per iniziare, aprire la AtApplicationStartup.aspx pagina nella Caching cartella . Trascinare un controllo GridView dalla casella degli strumenti nella finestra di progettazione, impostandone la ID proprietà su Suppliers. Successivamente, dallo smart tag di GridView scegliere di creare un nuovo ObjectDataSource denominato SuppliersCachedDataSource. Configurare ObjectDataSource per l'uso del StaticCache metodo della GetSuppliers() classe.

Configurare ObjectDataSource per l'uso della classe StaticCache

Figura 5: Configurare ObjectDataSource per l'uso della classe (fare clic per visualizzare l'immagineStaticCache a dimensione intera)

Utilizzare il metodo GetSuppliers() per recuperare i dati dei fornitori memorizzati nella cache

Figura 6: Usare il GetSuppliers() metodo per recuperare i dati dei fornitori memorizzati nella cache (fare clic per visualizzare l'immagine a dimensione intera)

Al termine della procedura guidata, Visual Studio aggiungerà automaticamente BoundFields per ognuno dei campi dati in SuppliersDataTable. Il markup dichiarativo di GridView e ObjectDataSource dovrebbe essere simile al seguente:

<asp:GridView ID="Suppliers" runat="server" AutoGenerateColumns="False" 
    DataKeyNames="SupplierID" DataSourceID="SuppliersCachedDataSource" 
    EnableViewState="False">
    <Columns>
        <asp:BoundField DataField="SupplierID" HeaderText="SupplierID" 
            InsertVisible="False" ReadOnly="True" 
            SortExpression="SupplierID" />
        <asp:BoundField DataField="CompanyName" HeaderText="CompanyName" 
            SortExpression="CompanyName" />
        <asp:BoundField DataField="Address" HeaderText="Address" 
            SortExpression="Address" />
        <asp:BoundField DataField="City" HeaderText="City" 
            SortExpression="City" />
        <asp:BoundField DataField="Country" HeaderText="Country" 
            SortExpression="Country" />
        <asp:BoundField DataField="Phone" HeaderText="Phone" 
            SortExpression="Phone" />
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="SuppliersCachedDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetSuppliers" TypeName="StaticCache" />

La figura 7 mostra la pagina visualizzata tramite un browser. L'output è lo stesso che è stato eseguito il pull dei dati dalla classe BLL, ma l'uso della StaticCache classe restituisce i dati del fornitore memorizzati nella cache all'avvio dell'applicazioneSuppliersBLL. È possibile impostare punti di interruzione nel StaticCache metodo della GetSuppliers() classe per verificare questo comportamento.

I dati dei fornitori memorizzati nella cache vengono visualizzati in un controllo GridView

Figura 7: I dati dei fornitori memorizzati nella cache vengono visualizzati in un controllo GridView (fare clic per visualizzare un'immagine a dimensione intera)

Riepilogo

La maggior parte di ogni modello di dati contiene una quantità equa di dati statici, in genere implementata sotto forma di tabelle di ricerca. Poiché queste informazioni sono statiche, non esiste alcun motivo per accedere continuamente al database ogni volta che queste informazioni devono essere visualizzate. Inoltre, a causa della sua natura statica, quando si memorizzano nella cache i dati non sono necessari per una scadenza. In questa esercitazione è stato illustrato come accettare tali dati e memorizzarlo nella cache dei dati, nello stato dell'applicazione e tramite una variabile membro statica. Queste informazioni vengono memorizzate nella cache all'avvio dell'applicazione e rimangono nella cache per tutta la durata dell'applicazione.

In questa esercitazione e nelle ultime due sono stati esaminati i dati di memorizzazione nella cache per la durata dell'applicazione e l'uso delle scadenze basate sul tempo. Quando si memorizzano nella cache i dati del database, tuttavia, una scadenza basata sul tempo può essere inferiore all'ideale. Anziché scaricare periodicamente la cache, sarebbe consigliabile rimuovere solo l'elemento memorizzato nella cache quando i dati del database sottostanti vengono modificati. Questa soluzione ideale è possibile tramite l'uso delle dipendenze della cache SQL, che verranno esaminate nell'esercitazione successiva.

Buon programmatori!

Informazioni sull'autore

Scott Mitchell, autore di sette libri ASP/ASP.NET e fondatore di 4GuysFromRolla.com, lavora con le tecnologie Web Microsoft dal 1998. Scott lavora come consulente indipendente, formatore e scrittore. Il suo ultimo libro è Sams Teach Yourself ASP.NET 2.0 in 24 ore. Può essere raggiunto all'indirizzo mitchell@4GuysFromRolla.com. o tramite il suo blog, disponibile all'indirizzo http://ScottOnWriting.NET.

Grazie speciale a

Questa serie di esercitazioni è stata esaminata da molti revisori utili. I revisori principali per questa esercitazione sono stati Teresa Murphy e Zack Jones. Si è interessati a esaminare i prossimi articoli MSDN? In tal caso, rilasciami una riga in mitchell@4GuysFromRolla.com.