O cache é uma técnica de armazenamento temporário de dados frequentemente acessados para reduzir o tempo de resposta e a carga de processamento. Ele permite que as aplicações armazenem informações em memória, evitando chamadas repetidas a bancos de dados, APIs ou serviços externos, melhorando o desempenho e a escalabilidade das aplicações.
O cache híbrido no ASP.NET Core combina o cache em memória (local) com o cache distribuído (remoto), oferecendo maior resiliência e eficiência. O cache local proporciona respostas rápidas, enquanto o cache remoto garante persistência de dados entre reinicializações de aplicativos. Para mais detalhes, acesse a documentação oficial do Hybrid Cache no ASP.NET Core.
Para começar, criamos o diretório raiz do projeto com o comando:
mkdir HybridCacheAspNet
Depois, entramos no diretório e criamos o projeto Web API em .NET com o comando:
dotnet new webapi
Agora, instalaremos os pacotes NuGet necessários para o projeto:
dotnet add package Microsoft.Extensions.Caching.Hybrid --version "9.0.0-preview.7.24406.2"
dotnet add package AspNetCore.Scalar
dotnet add package Microsoft.Extensions.Caching.StackExchangeRedis
Com os pacotes instalados, vamos criar os recursos de nuvem no Azure. Primeiro, faça login no Azure:
az login
Após o login, selecione a subscription com os comandos abaixo:
az account list --output table
az account set --subscription <subscription-id>
Crie um grupo de recursos no Azure com o comando:
az group create --name rg-hybrid-cache-eastus --location eastus
Agora, criamos o serviço Azure Cache for Redis:
az redis create --name redis-hybrid-cache-eastus --resource-group rg-hybrid-cache-eastus --location eastus --sku basic --vm-size C0
Podemos iniciar o desenvolvimento do app. Primeiro, iremos criar um método que retorna dados fictícios de um banco de dados:
Task<string> GetStringFromDbAsync(CancellationToken token)
{
return Task.FromResult(DateTime.UtcNow.ToString("dd/MM/yyyy - HH:mm:ss"));
}
Depois, criamos o método que verifica se os dados estão no cache ou no banco:
async Task<string> GetStringAsync(HybridCache cache, string key, CancellationToken token = default)
{
return await cache.GetOrCreateAsync(
key,
async cancel => await GetStringFromDbAsync(cancel),
cancellationToken: token
);
}
O que o código acima faz: ele verifica se a chave informada (key
) está presente no cache. Se os dados não estiverem no cache, o método GetStringFromDbAsync
é chamado para buscar a informação. Os dados buscados são armazenados no cache e retornados.
Agora, podemos criar o endpoint que consome o cache no ASP.NET Core:
app.MapGet("/get-cached-string", async (HybridCache cache, CancellationToken token) =>
{
string myKey = "my-key";
string value = await GetStringAsync(cache, myKey, token);
return Results.Ok(value);
})
.WithName("GetCachedString");
Vamos configurar o Hybrid Cache (cache local apenas) com o seguinte código:
builder.Services.AddHybridCache(options =>
{
options.DefaultEntryOptions = new HybridCacheEntryOptions
{
LocalCacheExpiration = TimeSpan.FromSeconds(10)
};
});
Agora, configuramos o Scalar para visualizar a API e fazer requisições de forma amigável. Leia a documentação oficial do scalar!
app.MapScalarApiReference(options =>
{
// Fluent API
options
.WithTitle("Hybrid cache API")
.WithModels(false)
.WithDefaultHttpClient(ScalarTarget.CSharp, ScalarClient.HttpClient)
.WithTheme(ScalarTheme.Saturn);
});
Para executar o projeto, rodamos o comando abaixo:
dotnet run
Na interface do Scalar, vamos fazer várias requisições ao endpoint /get-cached-string
. Podemos observar, que o valor retornado se mantém igual para todas as requisições em uma janela de 10 segundos, devido à configuração do cache local.
![](https://www.azurebrasil.cloud/content/images/2024/12/Screenshot-2024-12-06-at-15.25.28.png)
![](https://www.azurebrasil.cloud/content/images/2024/12/Screenshot-2024-12-06-at-15.25.41.png)
Agora, vamos criar outro endpoint que retorna um objeto complexo. Primeiro, criamos as classes, depois os métodos necessários e por fim, o novo endpoint:
class MyItem
{
public Guid Id { get; set; }
}
Task<MyItem> GetValueFromDbAsync(CancellationToken token)
{
return Task.FromResult(new MyItem
{
Id = Guid.NewGuid()
});
}
async Task<MyItem> GetValueAsync(HybridCache cache, string key, CancellationToken token = default)
{
return await cache.GetOrCreateAsync(
key,
async cancel => await GetValueFromDbAsync(cancel),
cancellationToken: token
);
}
app.MapGet("/get-cached-item", async (HybridCache cache, CancellationToken token) =>
{
string myKey = "my-item";
MyItem value = await GetValueAsync(cache, myKey, token);
return Results.Ok(value);
})
.WithName("GetCachedItem");
Podemos refazer o teste anterior! Vamos verificar que os valores dos objetos complexos retornados se mantém iguais dentro da janela de 10 segundos
![](https://www.azurebrasil.cloud/content/images/2024/12/Screenshot-2024-12-06-at-15.29.21.png)
Caso duas requisições sejam feitas com mais de 10 segundos entre elas, os valores retornados serão diferentes!
![](https://www.azurebrasil.cloud/content/images/2024/12/Screenshot-2024-12-06-at-15.29.33.png)
Agora vamos configurar o Redis remoto no Azure. Primeiro, obtemos a connection string do Redis no portal do Azure
![](https://www.azurebrasil.cloud/content/images/2024/12/Screenshot-2024-12-16-at-14.00.26.png)
Depois, adicionamos a configuração no arquivo appsettings.json
:
"ConnectionStrings": {
"RedisConnectionString": "<your-connection-string>"
}
Com a connection string configurada, ajustamos o código do cache para utilizar o Redis:
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration =
builder.Configuration.GetConnectionString("RedisConnectionString");
});
builder.Services.AddHybridCache(options =>
{
options.DefaultEntryOptions = new HybridCacheEntryOptions
{
Expiration = TimeSpan.FromSeconds(60),
LocalCacheExpiration = TimeSpan.FromSeconds(10)
};
});
Com essa configuração, os valores serão mantidos no cache local por 10 segundos e no cache remoto por 60 segundos. Agora, rodamos o projeto novamente e iremos fazer novas requisições para o endpoint get-cached-string.
Em seguida, reiniciamos a aplicação e, ao realizar uma nova requisição, notamos que o valor foi mantido, pois estava armazenado no Redis remoto.
![](https://www.azurebrasil.cloud/content/images/2024/12/Screenshot-2024-12-16-at-14.06.03.png)
Para finalizar, deletamos os recursos de nuvem utilizados para evitar cobranças:
az group delete --resource-group rg-hybrid-cache-eastus -y
Dessa forma, implementamos o Hybrid Cache no ASP.NET Core, utilizando cache local e remoto (Redis), com endpoints que demonstram o comportamento do cache. Também configuramos o Scalar para facilitar a visualização e consulta dos endpoints.
Você já pode baixar o projeto por esse link, e não esquece de me seguir no LinkedIn!
Até a próxima, abraços!