Ao se realizar uma requisição à um servidor web, toda uma cadeia de eventos é realizada para geração e renderização da página e recursos solicitados. Se uma página contém recursos que demandam um grande processamento, como exemplo uma consulta robusta a base dados, a cada requisição todo o processamento deverá ser realizado, mesmo se não houver nenhuma alteração nas informações coletadas. Logo, se a página acessa informações que não mudam frequentemente fica evidente o gasto desnecessário de recursos do servidor.

Para contornar essas situações, seria interessante a utilização de um mecanismo que nos permitisse armazenar as informações necessárias e só exigisse o processamento para obtenção do recurso quando fosse realmente necessário.

O Asp.Net provê este mecanismo através do caching, técnica que permite que objetos ou até mesmo páginas inteiras sejam armazenadas em memória, permitindo assim um rápido acesso ao conteúdo requisitado e sem a necessidade de lidar com complexidades como gerenciamento de memória ou atualização e expiração das informações em cache.

Este artigo tenta mostrar de forma simples como utilizar o caching no Asp.Net para aumento de desempenho e escalabilidade das aplicações web.

Tipos de caching

O Asp.Net provê dois tipo de caching: o caching de aplicação (Application caching) e o de página (Output Page caching). A seguir, uma definição dos dois:

  • Application caching: Funciona como uma lista de objetos armazenados na memória, basicamente como os objetos de gerenciamento de estado Session ou Aplication. Os itens armazenados a lista possuem escopo de aplicação, ou seja, são compartilhados por todas na aplicação web.
  • Page output caching: Este tipo de caching armazena páginas renderizadas, porções da página ou versões dela. Quando utilizado, a requisição recebe uma cópia que está na memória, não sendo necessário nenhum processamento para geração da mesma.

Application caching

O cahcing de aplicação é o processo de armazenar objetos na memória para acesso rápido, evitando a necessidade de processamento para obtenção dos resultados. Este tipo de caching pode ser utilizado de forma idêntica aos objetos Session ou Application. Como eles, consiste em uma lista de objetos referenciados por uma chave e pode ser acessado através da propriedade Cache do objeto Page. Adiante um exemplo de sua utilização:

Listagem 1: Application caching


public partial ApplictionCaching : System.Web.UI.Page
{
	protected void Page_Load(object sender, EventArgs e)
	{
		if(Page.Chace["DataHora"] == null)
			Page.Cache["DataHora"] = DateTime.Now;
		lblTime.Text = ((DateTime)Page.Cache["DataHora"]).ToLongTimeString();
	}
}

Note no exemplo acima, que assim como o objeto Session é necessário realizar o cast para o determinado tipo de objeto no ato da extração da informação. Além disso, todo objeto inserido possui um escopo global, sendo compartilhado por toda aplicação entre seções e requisições.

Método Insert

O Asp.Net através do método Insert provê uma forma mais sofisticada para implementar este tipo de caching. Habilitando controle a preciosas funcionalidades como tempo limite para expiração das informações, dependência de caching com outros objetos, configuração de prioridade e função de callback para o evento de remoção. Adiante um exemplo da utilização do método Insert:

Listagem 2: Método Insert

Page.Cache.Insert("DateTime", DateTime.Now);

Este exemplo mostra a forma mais simples de utilização do método, mas é possível realizar operações de caching mais sofisticadas. A seguir, as funcionalidades adicionais do método Insert:

Dependência de caching:

É possível vincular o período em que a informação no cache é válida através da relação com outros objetos. Um exemplo seria que uma determinada informação em cache só é valida até que um determinado arquivo no servido não seja atualizado, quando for, será necessário atualizar o conteúdo do cache. Essa funcionalidade é possível através da configuração do parâmetro dependencies, este parâmetro é um objeto CacheDependency, pertencente ao namespace System.Web.Caching.

O exemplo a seguir mostra como realizar o caching do conteúdo de um arquivo de texto e configurar a dependência de modo que quando o arquivo de texto for alterado o objeto será removido do cache.

Listagem 3: Caching de conteúdo


//Caching com dependência
if(Page.Cache["TextFile"] == null)
{
Page.Cache.Insert("TextFile", File.ReadAllText(Server.MapPath("~/ApplicationCaching/TextFile.txt")),
	new System.Web.Caching.CacheDependency(Server.MapPath("~/ApplicationCaching/TextFile.txt")));
}

No exemplo acima, quando a página é carregada o conteúdo do arquivo de texto é adicionado ao cache e é configurada à dependência para que o cache seja válido até ocorrer uma alteração no arquivo de origem. Se a alteração ocorre, o conteúdo é removido do cache.

Configurando tempo de validade do caching

Existem duas possibilidades para configurar o tempo de vida de um objeto no cache. A primeira é configurando a propriedade absoluteExpiration, que representa um objeto DateTime indicando um tempo futuro onde o conteúdo do cache não será mais válido e por conseqüência excluído. Utilizando este parâmetro não importa se o conteúdo está sendo acessado com freqüência, quando chegar momento configurado para expiração será excluído. O exemplo abaixo mostra como configurar a propriedade para que o cache seja invalidado no dia 12/12/2012.

Listagem 4: Invalidando o cache


//Caching por tempo absoluto
if(Page.Cache["AbsoluteTime "] == null)
{
	Page.Cache.Insert("AbsoluteTime",
				  DateTime.Now,
				  null,
				  new System.DateTime(2012,12,12),
				  new System.Web.Caching.Cache.NoSlidingExpiration);
}

Ao utilizar a sobrecarga do método que inclui o parâmetro absoluteExpiration é necessário informar o parâmetro slidingExpiration, que será visto mais adiante. Para informar ao método que não irá utilizá-lo é necessário informar a constante System.Web.Caching.Cache.NoSlidingExpiration, o mesmo acontece com o parâmetro absoluteExpiration, se não quiser utilizá-lo deve-se usar a constante System.Web.Caching.Cache.NoAbsoluteExpiration.

A segunda forma é configurando o parâmetro slidingExpiration, um objeto TimeSpan, que indica a quantidade de tempo desde o último acesso ao conteúdo em que o cache será válido. Ou seja, quando esse parâmetro é informado será levado em consideração se o conteúdo foi acessado recentemente. Assim que o caching for executado, uma contagem regressiva irá iniciar, se o cache for acessado antes do término da contagem, ela irá reiniciar se não, o objeto será removido. Abaixo segue um exemplo da configuração do parâmetro para que se após um minuto o conteúdo não for acessado seja removido do cache.

Listagem 5: Removendo cache após 1 minuto


//Caching por tempo decorrido
if(Page.Cache["SlidingTime"] == null)
{
	Page.Cache.Insert("SlidingTime",
				  DateTime.Now,
				  null,
				  new System.DateTime(2012,12,12),
				  new System.Web.Caching.Cache.NoAbsoluteExpiration,
				  new TimeSpan(0,1,0));
}

Configurando a prioridade dos objetos em cache

Quando a memória disponível para o caching começa a ficar escassa, o Asp.Net inicia o processo de scavenging, responsável pela remoção dos objetos mas antigos no cache e que não foram recentemente acessados. Se ele encontrar mais de um item com essas característica terá que comparar qual é mais prioritário, faz isto verificando a propriedade priority do objeto em cache. Para configurar essa propriedade deve-se passa como parâmetro no método Insert um item da enumeração System.Web.Caching.CacheItemPriority, que pode assumir os seguintes valores por ordem de prioridade:

  • NotRemovable
  • High
  • AboveNormal
  • Normal (mesmo que Default)
  • BelowNormal
  • Low

Função callback de remoção

O Asp.Net oferece uma função de callback para o evento de remoção de objetos do cache. Para ter acesso ao evento é necessário configurar o parâmetro onRemoveCallback, que é um delegate do tipo System.Web.Caching.CacheItemRemovedCallback, que recebe métodos com a seguinte assinatura:

Listagem 6: Função CallBack de Remoção

void (String, object, System.Web.Caching.CacheItemRemovedReason)

Após o objeto ser removido do cache, o método referenciado por esta propriedade é executado possibilitando realizar operações como, por exemplo, atualizar o conteúdo do cahce.

O exemplo abaixo utiliza o conteúdo de um arquivo de texto para o caching configurando a dependência para o arquivo de origem. Também é configurada a propriedade onRemoveCallback com o método UpdateCaching, com isso quando o arquivo de texto for alterado o conteúdo em cache será removido e o método UpdateCaching será executado atualizando o cache com o novo conteúdo do arquivo de texto.

Listagem 7: Atualizando o cache


public partial class ApplicationCaching_Insert : System.Web.UI.Page
{
	protected void Page_Load(object sender, EventArgs e)
	{
		//Caching com dependência
		if(Page.Cache["TextFile"] == null)
		{
			Page.Cache.Insert("TextFile",
								File.ReadAllText(Server.MapPath("~/ApplicationCaching/TextFile.txt")),
								new System.Web.Caching.CacheDependency(
									Server.MapPath("~/ApplicationCaching/TextFile.txt")),
								System.Web.Caching.Cache.NoAbsoluteExpiration,
								System.Web.Caching.Cache.NoSlidingExpiration,
								System.Web.Caching.CacheItemPriority.Normal,
								new System.Web.Caching.CacheItemRemovedCallBack(UpdateCaching));
		}
	}

	protected void UpdateCaching(String key, object item, System.Web.Caching.CacheItemRevovedReason reason)
	{
		Page.Cache.Insert("TextFile",
							File.ReadAllText(Server.MapPath("~/ApplicationCaching/TextFile.txt")),
							new System.Web.Caching.CacheDependency(
								Server.MapPath("~/ApplicationCaching/TextFile.txt")),
							System.Web.Caching.Cache.NoAbsoluteExpiration,
							System.Web.Caching.Cache.NoSlidingExpiration,
							System.Web.Caching.CacheItemPriority.Normal,
							new System.Web.Caching.CacheItemRemovedCallBack(UpdateCaching));
	}
}

Considerações finais

O mecanismo de caching do Asp.Net se utilizado de forma consciente torna-se uma poderosa ferramenta para proporcionar aumento de desempenho e escalabilidade da aplicação. Entretanto, deve-se tomar cuidado evitando seu uso exagerado e desnecessário, pois se mal utilizado, pode rapidamente esvaziar a memória destinada ao armazenamento e com isso anular seus benefícios.

Neste artigo abordei apenas o Application Caching para não deixá-lo muito extenso. Em um próximo artigo estarei comentando a respeito da segunda forma de caching, o Page Output Caching.

Referências

NORTHRUP, Tony; SNELL, Mike.; MCTS Self-Paced Training Kit (Exam 70-515) - Web Applications Development with Microsoft .NET Framework 4.

MACDONALD, Matthew; FREEMAN, Adam; SZPUSZTA Mario. Pro Asp.Net 4 in C# 2010. 4. Ed.