Condividi tramite


Miglioramento delle prestazioni con la cache di output (C#)

di Microsoft

In questa esercitazione si apprenderà come migliorare notevolmente le prestazioni delle applicazioni Web ASP.NET MVC sfruttando la memorizzazione nella cache dell'output. Si apprenderà come memorizzare nella cache il risultato restituito da un'azione del controller in modo che non sia necessario creare lo stesso contenuto e ogni volta che un nuovo utente richiama l'azione.

L'obiettivo di questa esercitazione è spiegare come migliorare notevolmente le prestazioni di un'applicazione MVC ASP.NET sfruttando la cache di output. La cache di output consente di memorizzare nella cache il contenuto restituito da un'azione del controller. In questo modo, lo stesso contenuto non deve essere generato ogni e ogni volta che viene richiamata la stessa azione del controller.

Si supponga, ad esempio, che l'applicazione MVC ASP.NET visualizzi un elenco di record di database in una vista denominata Index. In genere, ogni e ogni volta che un utente richiama l'azione controller che restituisce la vista Indice, il set di record di database deve essere recuperato dal database eseguendo una query di database.

Se invece si sfrutta la cache di output, è possibile evitare di eseguire una query di database ogni volta che qualsiasi utente richiama la stessa azione del controller. La vista può essere recuperata dalla cache invece di essere rigenerata dall'azione del controller. La memorizzazione nella cache consente di evitare di eseguire operazioni ridondanti nel server.

Abilitazione della memorizzazione nella cache dell'output

È possibile abilitare la memorizzazione nella cache dell'output aggiungendo un attributo [OutputCache] a una singola azione del controller o a un'intera classe controller. Ad esempio, il controller nell'elenco 1 espone un'azione denominata Index(). L'output dell'azione Index() viene memorizzato nella cache per 10 secondi.

Elenco 1 : Controllers\HomeController.cs

using System.Web.Mvc;

namespace MvcApplication1.Controllers
{
    [HandleError]
    public class HomeController : Controller
    {
        [OutputCache(Duration=10, VaryByParam="none")]
        public ActionResult Index()
        {
            return View();
        }
    }
}

Nelle versioni beta di ASP.NET MVC, la memorizzazione nella cache dell'output non funziona per un URL come http://www.MySite.com/. È invece necessario immettere un URL come http://www.MySite.com/Home/Index.

Nell'elenco 1 l'output dell'azione Index() viene memorizzato nella cache per 10 secondi. Se si preferisce, è possibile specificare una durata della cache molto più lunga. Ad esempio, se si desidera memorizzare nella cache l'output di un'azione del controller per un giorno, è possibile specificare una durata della cache di 86400 secondi (60 secondi * 60 minuti * 24 ore).

Non esiste alcuna garanzia che il contenuto venga memorizzato nella cache per il periodo di tempo specificato. Quando le risorse di memoria diventano ridotte, la cache avvia automaticamente la rimozione del contenuto.

Il controller Home nell'elenco 1 restituisce la visualizzazione Indice nell'elenco 2. Non c'è niente di speciale su questa vista. La visualizzazione Indice visualizza semplicemente l'ora corrente (vedere la figura 1).

Listato 2 : Views\Home\Index.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="MvcApplication1.Views.Home.Index" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Index</title>
</head>
<body>
    <div>
    
    The current time is: <%= DateTime.Now.ToString("T") %>
    
    
    </div>
</body>
</html>

Figura 1 : visualizzazione Indice memorizzato nella cache

clip_image002

Se si richiama l'azione Index() più volte immettendo l'URL /Home/Index nella barra degli indirizzi del browser e premendo ripetutamente il pulsante Aggiorna/Ricarica nel browser, l'ora visualizzata dalla visualizzazione Indice non cambierà per 10 secondi. Viene visualizzata la stessa ora perché la visualizzazione viene memorizzata nella cache.

È importante comprendere che la stessa visualizzazione viene memorizzata nella cache per tutti gli utenti che visitano l'applicazione. Chiunque richiami l'azione Index() otterrà la stessa versione memorizzata nella cache della visualizzazione Indice. Ciò significa che la quantità di lavoro che il server Web deve eseguire per gestire la visualizzazione Indice è notevolmente ridotta.

La visualizzazione nell'elenco 2 sta facendo qualcosa di davvero semplice. La visualizzazione visualizza solo l'ora corrente. Tuttavia, è possibile memorizzare facilmente nella cache una vista che visualizza un set di record di database. In tal caso, il set di record di database non deve essere recuperato dal database e ogni volta che viene richiamata l'azione del controller che restituisce la vista. La memorizzazione nella cache può ridurre la quantità di lavoro che deve essere eseguita sia dal server Web che dal server di database.

Non usare la direttiva %@ OutputCache %> della pagina <in una visualizzazione MVC. Questa direttiva sta sanguinando dal mondo Web Forms e non deve essere usata in un'applicazione ASP.NET MVC.

Dove il contenuto viene memorizzato nella cache

Per impostazione predefinita, quando si usa l'attributo [OutputCache], il contenuto viene memorizzato nella cache in tre posizioni: il server Web, i server proxy e il Web browser. È possibile controllare esattamente dove viene memorizzato il contenuto nella cache modificando la proprietà Location dell'attributo [OutputCache].

È possibile impostare la proprietà Location su uno dei valori seguenti:

· Qualsiasi

· Client

· Downstream

· Server

· Nessuno

· ServerAndClient

Per impostazione predefinita, la proprietà Location ha il valore Any. Tuttavia, esistono situazioni in cui è possibile memorizzare nella cache solo nel browser o solo nel server. Ad esempio, se si memorizzano nella cache le informazioni personalizzate per ogni utente, non è consigliabile memorizzare nella cache le informazioni nel server. Se vengono visualizzate informazioni diverse per utenti diversi, è necessario memorizzare nella cache le informazioni solo sul client.

Ad esempio, il controller nell'elenco 3 espone un'azione denominata GetName() che restituisce il nome utente corrente. Se Jack accede al sito Web e richiama l'azione GetName(), l'azione restituisce la stringa "Hi Jack". Se, successivamente, Jill accede al sito Web e richiama l'azione GetName(), riceverà anche la stringa "Hi Jack". La stringa viene memorizzata nella cache nel server Web per tutti gli utenti dopo che Jack richiama inizialmente l'azione del controller.

Elenco 3: Controllers\BadUserController.cs

using System.Web.Mvc;
using System.Web.UI;

namespace MvcApplication1.Controllers
{
    public class BadUserController : Controller
    {
        [OutputCache(Duration = 3600, VaryByParam = "none")]
        public string GetName()
        {
            return "Hi " + User.Identity.Name;
        }
    }
}

Molto probabilmente, il controller nell'elenco 3 non funziona nel modo desiderato. Non vuoi visualizzare il messaggio "Hi Jack" a Jill.

Non memorizzare mai nella cache del server il contenuto personalizzato. Tuttavia, è possibile memorizzare nella cache il contenuto personalizzato nella cache del browser per migliorare le prestazioni. Se si memorizza nella cache il contenuto nel browser e un utente richiama più volte la stessa azione del controller, il contenuto può essere recuperato dalla cache del browser anziché dal server.

Il controller modificato nell'elenco 4 memorizza nella cache l'output dell'azione GetName(). Tuttavia, il contenuto viene memorizzato nella cache solo nel browser e non nel server. In questo modo, quando più utenti richiamano il metodo GetName(), ogni persona ottiene il proprio nome utente e non il nome utente di un'altra persona.

Elenco 4 : Controllers\UserController.cs

using System.Web.Mvc;
using System.Web.UI;

namespace MvcApplication1.Controllers
{
    public class UserController : Controller
    {
        [OutputCache(Duration=3600, VaryByParam="none", Location=OutputCacheLocation.Client, NoStore=true)]
        public string GetName()
        {
            return "Hi " + User.Identity.Name;
        }
    }
}

Si noti che l'attributo [OutputCache] nell'elenco 4 include una proprietà Location impostata sul valore OutputCacheLocation.Client. L'attributo [OutputCache] include anche una proprietà NoStore. La proprietà NoStore viene utilizzata per informare i server proxy e il browser che non devono archiviare una copia permanente del contenuto memorizzato nella cache.

Variabile della cache di output

In alcune situazioni, è possibile che si vogliano versioni memorizzate nella cache diverse dello stesso contenuto. Si supponga, ad esempio, di creare una pagina master/dettagli. Nella pagina master viene visualizzato un elenco di titoli dei film. Quando si fa clic su un titolo, si ottengono i dettagli per il film selezionato.

Se memorizza nella cache la pagina dei dettagli, i dettagli per lo stesso film verranno visualizzati indipendentemente dal filmato che si fa clic. Il primo filmato selezionato dal primo utente verrà visualizzato a tutti gli utenti futuri.

È possibile risolvere questo problema sfruttando la proprietà VaryByParam dell'attributo [OutputCache]. Questa proprietà consente di creare versioni diverse memorizzate nella cache dello stesso contenuto quando un parametro di modulo o un parametro di stringa di query varia.

Ad esempio, il controller nell'elenco 5 espone due azioni denominate Master() e Details(). L'azione Master() restituisce un elenco di titoli dei film e l'azione Details() restituisce i dettagli per il filmato selezionato.

Elenco 5 : Controllers\MoviesController.cs

using System.Linq;
using System.Web.Mvc;
using MvcApplication1.Models;

namespace MvcApplication1.Controllers
{
    public class MoviesController : Controller
    {
        private MovieDataContext _dataContext;

        public MoviesController()
        {
            _dataContext = new MovieDataContext();
        }

        [OutputCache(Duration=int.MaxValue, VaryByParam="none")]
        public ActionResult Master()
        {
            ViewData.Model = (from m in _dataContext.Movies 
                              select m).ToList();
            return View();
        }

        [OutputCache(Duration = int.MaxValue, VaryByParam = "id")]
        public ActionResult Details(int id)
        {
            ViewData.Model = _dataContext.Movies.SingleOrDefault(m => m.Id == id);
            return View();
        }


    }
}

L'azione Master() include una proprietà VaryByParam con il valore "none". Quando viene richiamata l'azione Master(), viene restituita la stessa versione memorizzata nella cache della visualizzazione Master. Tutti i parametri di forma o di stringa di query vengono ignorati (vedere la figura 2).

Figura 2 : visualizzazione /Movies/Master

clip_image004

Figura 3 : visualizzazione /Movies/Details

clip_image006

L'azione Details() include una proprietà VaryByParam con il valore "Id". Quando vengono passati valori diversi del parametro Id all'azione del controller, vengono generate versioni memorizzate nella cache diverse della visualizzazione Dettagli.

È importante comprendere che l'uso della proprietà VaryByParam comporta una memorizzazione nella cache maggiore e non inferiore. Viene creata una versione memorizzata nella cache diversa della visualizzazione Dettagli per ogni versione diversa del parametro Id.

È possibile impostare la proprietà VaryByParam sui valori seguenti:

* = Creare una versione memorizzata nella cache diversa ogni volta che un parametro di forma o stringa di query varia.

none = Non creare mai versioni memorizzate nella cache diverse

Elenco punti e virgola dei parametri = Creare versioni memorizzate nella cache diverse ogni volta che uno dei parametri della maschera o della stringa di query nell'elenco varia

Creazione di un profilo cache

In alternativa alla configurazione delle proprietà della cache di output modificando le proprietà dell'attributo [OutputCache] è possibile creare un profilo cache nel file di configurazione Web (web.config). La creazione di un profilo di cache nel file di configurazione Web offre un paio di vantaggi importanti.

Prima di tutto, configurando la memorizzazione nella cache di output nel file di configurazione Web, è possibile controllare il modo in cui il contenuto della cache delle azioni del controller viene memorizzato in una posizione centrale. È possibile creare un profilo cache e applicare il profilo a diversi controller o azioni del controller.

In secondo luogo, è possibile modificare il file di configurazione Web senza ricompilare l'applicazione. Se è necessario disabilitare la memorizzazione nella cache per un'applicazione già distribuita in produzione, è sufficiente modificare i profili di cache definiti nel file di configurazione Web. Tutte le modifiche apportate al file di configurazione Web verranno rilevate automaticamente e applicate.

Ad esempio, la sezione cache> della configurazione Web nell'elenco <6 definisce un profilo di cache denominato Cache1Hour. La <sezione di memorizzazione nella cache> deve essere visualizzata all'interno della <sezione system.web> di un file di configurazione Web.

Elenco 6 - Sezione memorizzazione nella cache per web.config

<caching>
<outputCacheSettings>
    <outputCacheProfiles>
        <add name="Cache1Hour" duration="3600" varyByParam="none"/>
    </outputCacheProfiles>
</outputCacheSettings>
</caching>

Il controller nell'elenco 7 illustra come applicare il profilo Cache1Hour a un'azione del controller con l'attributo [OutputCache].

Elenco 7 - Controller\ProfileController.cs

using System;
using System.Web.Mvc;

namespace MvcApplication1.Controllers
{
    public class ProfileController : Controller
    {
        [OutputCache(CacheProfile="Cache1Hour")]
        public string Index()
        {
            return DateTime.Now.ToString("T");
        }
    }
}

Se si richiama l'azione Index() esposta dal controller nell'elenco 7, la stessa ora verrà restituita per 1 ora.

Riepilogo

La memorizzazione nella cache di output offre un metodo molto semplice per migliorare notevolmente le prestazioni delle applicazioni MVC ASP.NET. In questa esercitazione si è appreso come usare l'attributo [OutputCache] per memorizzare nella cache l'output delle azioni del controller. Si è anche appreso come modificare le proprietà dell'attributo [OutputCache] come le proprietà Duration e VaryByParam per modificare il modo in cui il contenuto viene memorizzato nella cache. Infine, si è appreso come definire i profili cache nel file di configurazione Web.