ASP.NET Core -  Implementando o Cache


Hoje veremos os conceitos do porquê e de como usar o Cache na ASP .NET Core em projetos  Web API.

Implementar a utilização do cache em sua aplicação ASP .NET Core adiciona mais uma camada de complexidade e para fazer isso você tem que ter bons motivos.

Então porque usar o cache ? Quais os seus benefícios ?

- Você economiza dinheiro (custos de largura de banda, menos servidores necessários, etc.)
- Proporciona uma melhor experiência para seus clientes;
- Seu sites ficam mais rápidos e ganham mais dinheiro e se classificam melhor no Google;
- Para sites que acessam banco de dados, armazenar as páginas entre as chamadas ao banco pode aumentar o desempenho da sua aplicação;

Tá bom assim , ou quer mais ???

Levando em conta os benefícios e o fato de que adicionar o cache na sua aplicação ASP .NET Core não é tão complicado assim, creio que deu pra te convencer a usar esse tal cache.

Desta vez vou abordar o uso do cache nas Web API da ASP .NET Core onde podemos implementar técnicas de cache da seguinte forma:

Obs: Existem ainda a opção de implementar o caching através de uma base de dados SQL Server.

Naturalmente tudo tem que ser feito com cuidado e com cautela, então vamos ao que interessa...

1 - Cache em Memória

O cache em memória para ASP .NET Core pode ser implementado com base na interface IMemoryCache que esta do namespace Microsoft.Extensions.Caching.Memory.

Para ativar o cache fazermos uma chamada a AddMemoryCache() no método ConfigureServices da classe Startup:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    services.AddMemoryCache();
}

O cache na memória é um service que é referenciado em seu aplicativo usando a injeção de dependência.

Para isso no controlador da aplicação onde vai usar o cache requisite a instância do IMemoryCache no construtor:

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;

namespace WebApi_MemoryCache.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class DemoController : ControllerBase
    {
          private readonly IMemoryCache _cache;
          public DemoController(IMemoryCache cache)
          {
             _cache = cache;
          }
     }
}

A seguir usamos a DI para injetar uma instância do cache no construtor e usamos essa instância para obter o cache e usar na aplicação:

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;

namespace WebApi_MemoryCache.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class DemoController : ControllerBase
    {
          private readonly IMemoryCache _cache;
          public DemoController(IMemoryCache cache)
          {
             _cache = cache;
          }
	 // GET: api/Demo/memorycache
	[HttpGet("memorycache")]
	public string Get()
	{
	    var cacheEntry = _cache.GetOrCreate("MeuCacheKey", entry =>
   	    {
  	       entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(10);
                  entry.SetPriority(CacheItemPriority.High);

	       return OperacaoDeLongaDuracao();
	     });
                return cacheEntry;
              }
          }
 	private string OperacaoDeLongaDuracao()
           {
	     Thread.Sleep(5000);
                return "Operação de longa duração concluída !";
           }
     }
}

Neste exemplo, usamos o método GetOrCreate que cria uma entrada na memória do servidor na primeira vez em que o usamos com uma entrada específica “MeuCacheKey”. O resultado da operação que precisa ser armazenado em cache é executado desta vez.

Na segunda vez que a operação é chamada, o método GetOrCreate verificará na memória se existe uma entrada com o “MeuCacheKey” e a carregará da memória. A operação que fornece o resultado não é executada.

Para a expiração do cache, é melhor usar a opção AbsoluteExpirationRelativeToNow porque o cache expirará após um tempo preciso, em vez de usar SlidingExpiration que expira após uma duração precisa, se o cache não tiver sido usado.

Desta forma, você garantirá que seus dados estarão atualizados após um determinado momento.

2- Cache distribuido com Redis

Um cache distribuído é um cache compartilhado por vários servidores, normalmente são mantidos como um serviço externo para os servidores que acessá-lo e pode melhorar o desempenho e escalabilidade de uma aplicação ASP.NET Core, especialmente quando o aplicativo é hospedado por um serviço de nuvem ou um farm de servidores.

Um cache distribuído tem várias vantagens sobre outros cenários de cache onde os dados armazenados em cache são armazenados em servidores de aplicativos individuais.

Quando os dados armazenados em cache são distribuídos, os dados:

O Redis é um repositório de dados na memória do código-fonte aberto, que geralmente é usado como um cache distribuído. Você pode usar o Redis localmente, e você pode configurar uma cache Rediz do Azure para um aplicativo ASP.NET Core hospedado no Azure.

A maneira mais simples de instalar o Redis no Windows é :

Para usar o Redis na ASP .NET Core temos que usar a interface IDistributedCache do namespace Microsoft.Extensions.Caching.Distributed.

A implementação é feita no método ConfigureServices da classe Startup usando uma instância de RedisCache fazendo a chamada a AddDistributedRedisCache() e informando a string de conexão com o Redis:

 public void ConfigureServices(IServiceCollection services)
 {
     // Ativa o uso de cache via Redis
     services.AddDistributedRedisCache(options =>
     {
         options.Configuration =
                Configuration.GetConnectionString("Conexao_Redis");
                options.InstanceName = "Demo_RedisCache";
      });
      services.AddMvc();
 }

Definindo a utilização no Controlador. Para o exemplo definir um controlador bem simples:

[Route("api/[controller]/[action]")]
[ApiController]

public class DemoRedisController : ControllerBase
{
   private readonly IDistributedCache _distributedCache;

   public DemoRedisController (IDistributedCache distributedCache)
   {
      this._distributedCache = distributedCache;
   }

   [HttpPut]
   public IActionResult SetValue([FromBody]CacheEntry entry)
   {
      this._distributedCache.SetString(entry.Key, entry.Value);
      return Ok();
   }

   [HttpGet]
   public IActionResult GetValue(string key)
   {
      var value = this._distributedCache.GetString(key);
      return Ok(value);
   }
}

Neste primeiro contato estamos interagindo com o Redis diretamente a partir dos controladores.

O IDistributedCache é injetado no construtor do controlador e, em seguida, há dois métodos, um dos quais adiciona uma nova entrada ao Redis (ou atualiza um se uma determinada chave já existir) e o outro que obtém o valor armazenado com uma determinada chave.

Em outro artigo mostrei uma implementação prática de cada uma dessas abordagens.

"Disse-lhe, pois, Pilatos: Logo tu és rei? Jesus respondeu: Tu dizes que eu sou rei. Eu para isso nasci, e para isso vim ao mundo, a fim de dar testemunho da verdade. Todo aquele que é da verdade ouve a minha voz."
João 18:37

Referências:


José Carlos Macoratti