> ## Content Index
> Fetch the complete content index at: https://www.azurebrasil.cloud/llms.txt
> Use this file to discover other available public pages before exploring further.

# Utilizando o HybridCache no ASP.NET Core
- URL: https://www.azurebrasil.cloud/blog/utilizando-o-hybridcache-no-asp-net-core/
- Published: 2024-12-17T17:07:42.000Z
- Updated: 2024-12-17T17:07:42.000Z
- Author: Talles Valiatti

O [cache](https://learn.microsoft.com/pt-br/aspnet/core/performance/caching/overview?view=aspnetcore-9.0&ref=azurebrasil.cloud) é 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](https://learn.microsoft.com/pt-br/aspnet/core/performance/caching/memory?view=aspnetcore-9.0&ref=azurebrasil.cloud)) com o [cache distribuído (remoto)](https://learn.microsoft.com/pt-br/aspnet/core/performance/caching/distributed?view=aspnetcore-9.0&ref=azurebrasil.cloud), 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](https://learn.microsoft.com/pt-br/aspnet/core/performance/caching/hybrid?view=aspnetcore-9.0&ref=azurebrasil.cloud) no ASP.NET Core.

Para começar, criamos o diretório raiz do projeto com o comando:

```bash
mkdir HybridCacheAspNet
```

Depois, entramos no diretório e criamos o projeto [Web API](https://learn.microsoft.com/pt-br/aspnet/core/tutorials/first-web-api?view=aspnetcore-9.0&tabs=visual-studio&ref=azurebrasil.cloud) em .NET com o comando:

```bash
dotnet new webapi
```

Agora, instalaremos os pacotes NuGet necessários para o projeto:

```bash
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:

```bash
az login
```

Após o [*login*](https://learn.microsoft.com/pt-br/cli/azure/authenticate-azure-cli?ref=azurebrasil.cloud), selecione a [*subscription*](https://learn.microsoft.com/pt-br/azure/cost-management-billing/manage/create-subscription?ref=azurebrasil.cloud) com os comandos abaixo:

```bash
az account list --output table
az account set --subscription <subscription-id>
```

Crie um [grupo de recursos no Azure](https://learn.microsoft.com/pt-br/azure/azure-resource-manager/management/manage-resource-groups-portal?ref=azurebrasil.cloud) com o comando:

```bash
az group create --name rg-hybrid-cache-eastus --location eastus
```

Agora, criamos o serviço [Azure Cache for Redis](https://learn.microsoft.com/pt-br/azure/azure-cache-for-redis/cache-overview?ref=azurebrasil.cloud):

```bash
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:

```csharp
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](https://learn.microsoft.com/pt-br/aspnet/core/performance/caching/hybrid?view=aspnetcore-9.0&ref=azurebrasil.cloud#get-and-store-cache-entries) ou no banco:

```csharp
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:

```csharp
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:

```csharp
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*](https://github.com/scalar/scalar/blob/main/packages/scalar.aspnetcore/README.md?ref=azurebrasil.cloud)!

```csharp
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:

```bash
dotnet run

```

Na interface do [Scalar](https://github.com/scalar/scalar?ref=azurebrasil.cloud), 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://storage.ghost.io/c/00/52/0052dced-0017-4d07-b190-1f5c48e0ab59/content/images/2024/12/Screenshot-2024-12-06-at-15.25.28.png)

![](https://storage.ghost.io/c/00/52/0052dced-0017-4d07-b190-1f5c48e0ab59/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*:

```csharp
class MyItem
{
    public Guid Id { get; set; }
}
```

```csharp
Task<MyItem> GetValueFromDbAsync(CancellationToken token)
{
    return Task.FromResult(new MyItem
    {
        Id = Guid.NewGuid()
    });
}
```

```csharp
async Task<MyItem> GetValueAsync(HybridCache cache, string key, CancellationToken token = default)
{
    return await cache.GetOrCreateAsync(
        key,
        async cancel => await GetValueFromDbAsync(cancel),
        cancellationToken: token
    );
}

```

```csharp
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://storage.ghost.io/c/00/52/0052dced-0017-4d07-b190-1f5c48e0ab59/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://storage.ghost.io/c/00/52/0052dced-0017-4d07-b190-1f5c48e0ab59/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://storage.ghost.io/c/00/52/0052dced-0017-4d07-b190-1f5c48e0ab59/content/images/2024/12/Screenshot-2024-12-16-at-14.00.26.png)

Depois, adicionamos a [configuração](https://tallesvaliatti.com/utilizando-as-configura%C3%A7%C3%B5es-em-aplicativos-net-f8e1ee9dff6e?ref=azurebrasil.cloud) no arquivo `appsettings.json`:

```csharp
  "ConnectionStrings": {
    "RedisConnectionString": "<your-connection-string>"
  }
```

Com a *connection string* configurada, ajustamos o código do cache para utilizar o Redis:

```csharp
builder.Services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = 
        builder.Configuration.GetConnectionString("RedisConnectionString");
});
```

```csharp
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://storage.ghost.io/c/00/52/0052dced-0017-4d07-b190-1f5c48e0ab59/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:

```bash
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](https://github.com/TallesValiatti/HybridCacheAspNet?ref=azurebrasil.cloud), e não esquece de me seguir no [LinkedIn](https://www.linkedin.com/in/tallesvaliatti/?ref=azurebrasil.cloud)!

Até a próxima, abraços!