Melhorar o desempenho com o cache de saída (C#)

pela Microsoft

Neste tutorial, você aprenderá a melhorar drasticamente o desempenho de seus aplicativos Web ASP.NET MVC aproveitando o cache de saída. Você aprenderá a armazenar em cache o resultado retornado de uma ação do controlador para que o mesmo conteúdo não precise ser criado toda vez que um novo usuário invocar a ação.

O objetivo deste tutorial é explicar como você pode melhorar drasticamente o desempenho de um aplicativo MVC ASP.NET aproveitando o cache de saída. O cache de saída permite armazenar em cache o conteúdo retornado por uma ação do controlador. Dessa forma, o mesmo conteúdo não precisa ser gerado sempre que a mesma ação do controlador é invocada.

Imagine, por exemplo, que seu aplicativo ASP.NET MVC exibe uma lista de registros de banco de dados em uma exibição chamada Index. Normalmente, cada vez que um usuário invoca a ação do controlador que retorna a exibição Índice, o conjunto de registros de banco de dados deve ser recuperado do banco de dados executando uma consulta de banco de dados.

Se, por outro lado, você tirar proveito do cache de saída, poderá evitar a execução de uma consulta de banco de dados sempre que qualquer usuário invocar a mesma ação do controlador. A exibição pode ser recuperada do cache em vez de ser regenerada da ação do controlador. O cache permite evitar a execução de trabalho redundante no servidor.

Habilitando o cache de saída

Habilite o cache de saída adicionando um atributo [OutputCache] a uma ação de controlador individual ou a uma classe de controlador inteira. Por exemplo, o controlador na Listagem 1 expõe uma ação chamada Index(). A saída da ação Index() é armazenada em cache por 10 segundos.

Listagem 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();
        }
    }
}

Nas versões Beta do ASP.NET MVC, o cache de saída não funciona para uma URL como http://www.MySite.com/. Em vez disso, você deve inserir uma URL como http://www.MySite.com/Home/Index.

Na Listagem 1, a saída da ação Index() é armazenada em cache por 10 segundos. Se preferir, você pode especificar uma duração de cache muito mais longa. Por exemplo, se você quiser armazenar em cache a saída de uma ação do controlador por um dia, poderá especificar uma duração de cache de 86400 segundos (60 segundos * 60 minutos * 24 horas).

Não há nenhuma garantia de que o conteúdo será armazenado em cache pela quantidade de tempo que você especificar. Quando os recursos de memória ficam baixos, o cache começa a remover conteúdo automaticamente.

O controlador Home na Listagem 1 retorna a exibição Índice na Listagem 2. Não há nada de especial neste modo de exibição. A exibição Índice simplesmente exibe a hora atual (consulte a Figura 1).

Listagem 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 – Exibição de índice armazenado em cache

clip_image002

Se você invocar a ação Index() várias vezes inserindo a URL /Home/Index na barra de endereços do navegador e pressionando o botão Atualizar/Recarregar repetidamente no navegador, o tempo exibido pelo modo de exibição Índice não será alterado por 10 segundos. O mesmo tempo é exibido porque o modo de exibição é armazenado em cache.

É importante entender que a mesma exibição é armazenada em cache para todos que visitam seu aplicativo. Qualquer pessoa que invocar a ação Index() obterá a mesma versão armazenada em cache da exibição Índice. Isso significa que a quantidade de trabalho que o servidor Web deve executar para atender à exibição índice é drasticamente reduzida.

O modo de exibição na Listagem 2 está fazendo algo muito simples. O modo de exibição apenas exibe a hora atual. No entanto, você poderia armazenar em cache facilmente uma exibição que exibe um conjunto de registros de banco de dados. Nesse caso, o conjunto de registros de banco de dados não precisaria ser recuperado do banco de dados toda vez que a ação do controlador que retorna a exibição fosse invocada. O cache pode reduzir a quantidade de trabalho que o servidor Web e o servidor de banco de dados devem executar.

Não use a página <%@ Diretiva OutputCache %> em um modo de exibição MVC. Essa diretiva está sangrando do mundo Web Forms e não deve ser usada em um aplicativo MVC ASP.NET.

Onde o conteúdo é armazenado em cache

Por padrão, quando você usa o atributo [OutputCache], o conteúdo é armazenado em cache em três locais: o servidor Web, todos os servidores proxy e o navegador da Web. Você pode controlar exatamente onde o conteúdo é armazenado em cache modificando a propriedade Location do atributo [OutputCache].

Você pode definir a propriedade Location como qualquer um dos seguintes valores:

· Qualquer

· Cliente

· Jusante

· Servidor

· Nenhum

· ServerAndClient

Por padrão, a propriedade Location tem o valor Any. No entanto, há situações em que talvez você queira armazenar em cache apenas no navegador ou somente no servidor. Por exemplo, se você estiver armazenando em cache informações personalizadas para cada usuário, não deverá armazenar em cache as informações no servidor. Se você estiver exibindo informações diferentes para usuários diferentes, deverá armazenar em cache as informações somente no cliente.

Por exemplo, o controlador na Listagem 3 expõe uma ação chamada GetName() que retorna o nome de usuário atual. Se Jack fizer logon no site e invocar a ação GetName(), a ação retornará a cadeia de caracteres "Hi Jack". Se, posteriormente, Jill fizer logon no site e invocar a ação GetName(), ela também obterá a cadeia de caracteres "Hi Jack". A cadeia de caracteres é armazenada em cache no servidor Web para todos os usuários depois que Jack inicialmente invoca a ação do controlador.

Listagem 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;
        }
    }
}

Provavelmente, o controlador na Listagem 3 não funciona da maneira desejada. Você não quer exibir a mensagem "Olá Jack" para Jill.

Você nunca deve armazenar em cache o conteúdo personalizado no cache do servidor. No entanto, talvez você queira armazenar em cache o conteúdo personalizado no cache do navegador para melhorar o desempenho. Se você armazenar em cache o conteúdo no navegador e um usuário invocar a mesma ação do controlador várias vezes, o conteúdo poderá ser recuperado do cache do navegador em vez do servidor.

O controlador modificado na Listagem 4 armazena em cache a saída da ação GetName(). No entanto, o conteúdo é armazenado em cache apenas no navegador e não no servidor. Dessa forma, quando vários usuários invocam o método GetName(), cada pessoa obtém seu próprio nome de usuário e não o nome de usuário de outra pessoa.

Listagem 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;
        }
    }
}

Observe que o atributo [OutputCache] na Listagem 4 inclui uma propriedade Location definida com o valor OutputCacheLocation.Client. O atributo [OutputCache] também inclui uma propriedade NoStore. A propriedade NoStore é usada para informar os servidores proxy e o navegador de que eles não devem armazenar uma cópia permanente do conteúdo armazenado em cache.

Variando o cache de saída

Em algumas situações, talvez você queira versões em cache diferentes do mesmo conteúdo. Imagine, por exemplo, que você está criando uma página de master/detalhes. A página master exibe uma lista de títulos de filmes. Ao clicar em um título, você obtém detalhes do filme selecionado.

Se você armazenar em cache a página de detalhes, os detalhes do mesmo filme serão exibidos independentemente de qual filme você clicar. O primeiro filme selecionado pelo primeiro usuário será exibido para todos os usuários futuros.

Você pode corrigir esse problema aproveitando a propriedade VaryByParam do atributo [OutputCache]. Essa propriedade permite que você crie diferentes versões armazenadas em cache do mesmo conteúdo quando um parâmetro de formulário ou parâmetro de cadeia de caracteres de consulta varia.

Por exemplo, o controlador na Listagem 5 expõe duas ações chamadas Master() e Details(). A ação Mestre() retorna uma lista de títulos de filme e a ação Detalhes() retorna os detalhes do filme selecionado.

Listagem 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();
        }


    }
}

A ação Master() inclui uma propriedade VaryByParam com o valor "none". Quando a ação Master() é invocada, a mesma versão armazenada em cache do modo de exibição Mestre é retornada. Todos os parâmetros de formulário ou parâmetros de cadeia de caracteres de consulta são ignorados (consulte a Figura 2).

Figura 2 – O modo de exibição /Movies/Master

clip_image004

Figura 3 – a exibição /Movies/Details

clip_image006

A ação Details() inclui uma propriedade VaryByParam com o valor "Id". Quando valores diferentes do parâmetro Id são passados para a ação do controlador, diferentes versões armazenadas em cache da exibição Detalhes são geradas.

É importante entender que usar a propriedade VaryByParam resulta em mais cache e não menos. Uma versão em cache diferente da exibição Detalhes é criada para cada versão diferente do parâmetro Id.

Você pode definir a propriedade VaryByParam para os seguintes valores:

* = Crie uma versão armazenada em cache diferente sempre que um parâmetro de cadeia de caracteres de formulário ou consulta varia.

none = Nunca criar versões em cache diferentes

Lista de parâmetros de ponto e vírgula = Criar diferentes versões armazenadas em cache sempre que qualquer um dos parâmetros de cadeia de caracteres de formulário ou consulta na lista varia

Criando um perfil de cache

Como alternativa à configuração das propriedades do cache de saída modificando as propriedades do atributo [OutputCache], você pode criar um perfil de cache no arquivo de configuração da Web (web.config). A criação de um perfil de cache no arquivo de configuração da Web oferece algumas vantagens importantes.

Primeiro, ao configurar o cache de saída no arquivo de configuração da Web, você pode controlar como as ações do controlador armazenam conteúdo em cache em um local central. Você pode criar um perfil de cache e aplicar o perfil a vários controladores ou ações do controlador.

Em segundo lugar, você pode modificar o arquivo de configuração da Web sem recompilar seu aplicativo. Se você precisar desabilitar o cache de um aplicativo que já foi implantado na produção, poderá simplesmente modificar os perfis de cache definidos no arquivo de configuração da Web. Todas as alterações no arquivo de configuração da Web serão detectadas automaticamente e aplicadas.

Por exemplo, a seção de configuração da <Web de cache> na Listagem 6 define um perfil de cache chamado Cache1Hour. A <seção de cache> deve aparecer na <seção system.web> de um arquivo de configuração da Web.

Listagem 6 – Seção cache para web.config

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

O controlador na Listagem 7 ilustra como você pode aplicar o perfil Cache1Hour a uma ação do controlador com o atributo [OutputCache].

Listagem 7 – Controllers\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 você invocar a ação Index() exposta pelo controlador na Listagem 7, o mesmo tempo será retornado por 1 hora.

Resumo

O cache de saída fornece um método muito fácil de melhorar drasticamente o desempenho de seus aplicativos ASP.NET MVC. Neste tutorial, você aprendeu a usar o atributo [OutputCache] para armazenar em cache a saída das ações do controlador. Você também aprendeu a modificar propriedades do atributo [OutputCache], como as propriedades Duration e VaryByParam para modificar como o conteúdo é armazenado em cache. Por fim, você aprendeu a definir perfis de cache no arquivo de configuração da Web.