Melhoria de Performance em ASP.NET utilizando Caching

 

O desafio de construir aplicações Web escaláveis e com alta performance está na habilidade de se armazenar itens em memória na primeira vez em que são utilizados, sejam objetos de dados, páginas ou fragmentos de página.

ASP.NET provê diferentes níveis de caching para você melhorar o tempo de resposta de suas aplicações, armazenando as páginas ou dados da aplicação através de requisições HTTP e reutilizando-os. Isto traz ao servidor web a vantagem de se processar as requisições sem precisar recriar as informações a cada requisição e assim economizar tempo e recursos.

Recursos de caching em página ASP.NET

ASP.NET suporta caching de página (ou fragmento de página) e caching de dados de uma fonte de dados e armazena esses objetos individuais em memória. Para isso, os seguintes recursos estão disponíveis no ASP.NET

Caching de página;

Caching de fragmento de página;

Caching de dados.

Caching de Página

Páginas .aspx geradas dinamicamente podem ser armazenadas para aumentar a eficiência, ao invés de se re-gerar a página para cada requisição idêntica. Caching de página pode ser realizada de 3 maneiras:

1) Pode ser realizado especificando-se a diretiva #OutputCache no topo da página ASP.NET. Isto controla a duração do cache (em segundos).

 

<%@ OutputCache Duration="3600" VaryByParam="none" %>

<html>

<script language="C#" runat="server">

void Page_Load(Object sender, EventArgs e) {

msg.Text = DateTime.Now.ToString();

}</script>

<body>

<h3>Output Cache example</font></h3>

<p>Last generated on: <asp:label id="msg" runat="server"/>

</body>

</html>

 

2) Outra forma de se realizar caching é utilizando a classe HttpCachePolicy (sealed), que pode ser acessada pela propriedade HttpResponse.Cache da propriedade Page.Response.

Classe HttpCachePolicy

public sealed class HttpCachePolicy

{

   public HttpCacheVaryByHeaders VaryByHeaders {get;}

   public HttpCacheVaryByParams VaryByParams {get;}

   public void AppendCacheExtension(string extension);

   public void SetCacheability(HttpCacheability cacheability);

   public void SetExpires(DateTime date);

   public void SetLastModified(DateTime date);

   public void SetMaxAge(TimeSpan delta);

   public void SetNoServerCaching();

   public void SetSlidingExpiration(bool slide);

   //...

}

 

 Modificando a política de caching de um página

 

<html>

<script language="C#" runat="server">

void Page_Load(Object sender, EventArgs e) {

Response.Cache.SetExpires(DateTime.Now.AddSeconds(360));

Response.Cache.SetCacheability(HttpCacheability.Public);

Response.Cache.SetSlidingExpiration(true);

msg.Text = DateTime.Now.ToString();

}

</script>

<body>

<h3>Output Cache example</font></h3>

<p>Last generated on: <asp:label id="msg" runat="server"/>

</body>

</html>

 

3) Caching de requisições GET com string de consulta ou requisições POST com corpo são controladas pela propriedade VaryByParam. Ela determina quantas versões da página serão armazenadas. Configurando a propriedade para “none” significa que apenas requisições GET sem string de consulta ou requisições POST sem corpo serão armazenadas no cache. Configurando VaryByParam para “*” significa que as diferentes strings de consulta ou corpos de requisição POST que são recebidas serão armazenadas.

A tabela a seguir resume os valores de VaryByParam

VaryByParam

Descrição

None

Uma versão da página será armazenada (apenas requisições GET sem parâmetros)

*

n versões são armazenadas baseando-se na string de consulta das requisições GET e/ou corpo das requisições POST

V1

n versões são armazenadas baseando-se no valor da variável V1 na string de consulta GET ou no corpo do POST

V1;V2

n versões são armazenadas baseando-se no valor das variáveis V1 e V2 na string de consulta GET ou no corpo do POST

 

 

 

 

 

 

 

 

 

 

 

<%@ OutputCache Duration="60" VaryByParam="none" %>

<%@ OutputCache Duration="60" VaryByParam="*" %>

<%@ OutputCache Duration="60" VaryByParam="name;age" %>

 

Na primeira vez que a página é requisitada, a resposta é gerada e adicionada ao cache. Se a página é requisitada novamente em 60 segundos, com os mesmos valores para “name” e “age”, então a página armazenada é utilizada.

Outras opções de cache

·         A diretiva OutputCache suporta diversas outras opções de cache

·         VaryByHeader – mantêm caches separados para diferenças no cabeçalho (UserAgent, UserLanguage, etc.)

·         VaryByControl – mantêm caches separados para propriedades de um controle do usuário

·         VaryByCustom – pode especificar caches separados para tipo e versão de browser ou prover um método GetVaryByCustomString customizado em uma classe derivada de HttpApplication.

Caching de Fragmentos de Página

Fragmentos de páginas ASP.NET que devem ser armazenadas em cache são encapsuladas em Web Forms User Controls. O exemplo de user control (MyUserControl.ascx) está abaixo. Este user control é inserido na página Client.aspx.

 

MyUserControl.ascx

<%@ OutputCache Duration="60" VaryByParam="none" %>

<%@ Control Language=C# %>

<script runat=server>

protected void Page_Load(Object src, EventArgs e)

{

m_Date.Text = "Control generated at " +

DateTime.Now.ToString();

}

</script>

<asp:Label id=m_Date runat=server />

 

Client.aspx

<%@ Page Language=C# %>

<%@ Register TagPrefix="DM" TagName="UserFrag"

Src="MyUserControl.ascx" %>

<html>

<script runat=server>

protected void Page_Load(Object src, EventArgs e)

{

m_PageDate.Text = "Page generated at " +

DateTime.Now.ToString();

}

</script>

<body>

<DM:UserFrag runat=server />

<br>

<asp:Label id=m_PageDate runat=server />

</body></html>

Caching de Dados

De forma simples, caching de dados consiste em armazenar dados em memória para acesso rápido. Normalmente informação que é custosa para se obter é armazenada em cache. Uns dos itens mais comumente armazenados em cache em aplicações Web são os dados utilizados com mais freqüência e que são provenientes de bancos de dados; armazenando esse tipo de informação, ao invés de se realizar repetidas chamadas ao banco de dados, a demanda do servidor Web e do servidor de banco de dados diminuem e a escalabilidade das aplicações Web aumentam.

ASP.NET provê um sistema de cache completo que pode ser utilizado pelas páginas para armazenar dados através das requisições HTTP.

Um pequeno exemplo de como armazenar um valor obtido do banco de dados está abaixo.

 

<%@ Import Namespace="System.Data" %>

<%@ Import Namespace="System.Data.SqlClient" %>

<html>

<script language="C#" runat="server">

protected void Page_Load(Object src, EventArgs e)

{ DataView dv = (DataView)Cache.Get("EmployeesDataView");

  if (dv == null) { // wasn't there

  SqlConnection conn = new SqlConnection("server=localhost;uid=sa;pwd=;database=Test");

  SqlDataAdapter da = new SqlDataAdapter("select * from Employees", conn);

  DataSet ds = new DataSet();

  da.Fill(ds, "Employees");

  dv = ds.Tables["Employees"].DefaultView;

  Cache.Insert("EmployeesDataView", dv);

  conn.Close();

}

else

  Response.Write("<h2>Loaded employees from data cache!</h2>");

  lb1.DataSource = dv;

  lb1.DataTextField = "Name";

  lb1.DataValueField = "Age";

  DataBind();

}

</script>

<body><asp:ListBox id="lb1" runat=server /></body>

</html>

Atributos do cache

·         Quando são feitas entradas no cache, alguns atributos podem ser configurados

·         Dependências (com arquivos, diretórios, ou outras entradas do cache)

·         Tempo de expiração (absoluto)

·         Período de expiração (cronômetro)

·         Prioridade relativa

·         Taxa de deterioração da prioridade

·         Função de callback para notificação de remoção

 

Os diferentes parâmetros que o método Insert aceita estão abaixo.

 

[C#]

public void Insert(string key, object value, CacheDependency dependencies,

   DateTime absoluteExpiration, TimeSpan slidingExpiration,

   CacheItemPriority priority, CacheItemRemovedCallback onRemoveCallback);

 

Parâmetros

Key: A chave utilizada para referenciar o objeto.

Value: O objeto a ser armazenado.

Dependencies: Os arquivos ou outras entradas do cache que o item possui relacionamento. Quando qualquer dependência é alterada, o objeto se torna inválido e é removido do cache. Se não existem dependências, este parâmetro contém uma referência a null.

AbsoluteExpiration: A hora (tempo absoluto) que o objeto inserido expira e é removido do cache.

SlidingExpiration:  O intervalo entre a hora que o objeto inserido foi acessado pela ultima vez e a hora que o objeto expira. Se este valor é equivalente a 20 minutos, o objeto irá expirar e será removido do cache 20 minutos após seu último acesso.

Priority: O custo do objeto em relação a outros itens armazenados no cache (valores de acordo com o enumeration CacheItemPriority). Este valor é utilizado pelo cache quando ele remove os objetos; objetos com um custo menor são removidos do cache antes que objetos com um custo maior.

onRemoveCallback: Um delegate, que quando fornecido, será chamado quando o objeto é removido do cache. Pode-se utilizar para notificar aplicações quando seus objetos são removidos do cache.

Removendo objetos do cache

• Objetos podem ser removidos do cache explicitamente chamando-se Remove

• O cache pode remover um item explicitamente por diversas razões

         Tempo expirado

Consumo de memória

• Dados com menor prioridade são removidos antes

• Valores marcados com Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration,

CacheItemPriority.NotRemovable, ou CacheItemPriorityDecay.Never nunca são removidos

• Pode ser registrado para notificação de remoção, incluindo a razão

Utilizando a notificação de remoção

<script language=C# runat=server>

public void Application_OnStart()

{

System.IO.StreamReader sr = new System.IO.StreamReader("pi.txt");

string pi = sr.ReadToEnd();

Context.Cache.Add("pi", pi, null, Cache.NoAbsoluteExpiration,

  new TimeSpan(0, 5, 0), CacheItemPriorityDecay.Never,

  new CacheItemReomovedCallback(this.OnRemove));

}

public void OnRemove(string key, object val, CacheItemRemovedReason r)

{

// respond to cache removal here

}

</script>

Desvantagens do Caching

Apesar do suporte a caching ser muito útil em diversos cenários, ele possui algumas desvantagens.

Ao se trabalhar com páginas armazenadas em cache que exibem dados adquiridos de um bando de dados, o cache pode ser inconsistente, por não refletir as últimas modificações feitas no banco de dados.

Conclusão

Caching melhora dramaticamente a performance de um web site, mas ao mesmo tempo possui suas desvantagens. O usuário precisa tomar cuidado com os valores utilizados nos parâmetros da política de expiração.