Libreria HybridCache in ASP.NET Core

Importante

HybridCache è attualmente ancora in anteprima, ma verrà completamente rilasciato dopo .NET 9.0 in una versione secondaria futura delle estensioni .NET.

Questo articolo illustra come configurare e usare la HybridCache libreria in un'app ASP.NET Core. Per un'introduzione alla libreria, vedere la HybridCache sezione della panoramica della memorizzazione nella cache.

Ottenere la libreria

Installare il pacchetto Microsoft.Extensions.Caching.Hybrid.

dotnet add package Microsoft.Extensions.Caching.Hybrid --version "9.0.0-preview.7.24406.2"

Registrare il servizio

Aggiungere il HybridCache servizio al contenitore di inserimento delle dipendenze chiamando AddHybridCache:

// Add services to the container.
var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddAuthorization();

builder.Services.AddHybridCache();

Il codice precedente registra il HybridCache servizio con le opzioni predefinite. L'API di registrazione può anche configurare opzioni e serializzazione.

Ottenere e archiviare le voci della cache

Il HybridCache servizio fornisce un GetOrCreateAsync metodo con due overload, prendendo una chiave e:

  • Metodo factory.
  • Stato e metodo factory.

Il metodo usa la chiave per tentare di recuperare l'oggetto dalla cache primaria. Se l'elemento non viene trovato nella cache primaria (un mancato riscontro nella cache), controlla la cache secondaria se ne è configurata una. Se non trova i dati (un altro mancato riscontro nella cache), chiama il metodo factory per ottenere l'oggetto dall'origine dati. Archivia quindi l'oggetto nelle cache primarie e secondarie. Il metodo factory non viene mai chiamato se l'oggetto viene trovato nella cache primaria o secondaria (un riscontro nella cache).

Il HybridCache servizio garantisce che un solo chiamante simultaneo per una determinata chiave chiami il metodo factory e tutti gli altri chiamanti attendino il risultato di tale chiamata. Oggetto CancellationToken passato a GetOrCreateAsync rappresenta l'annullamento combinato di tutti i chiamanti simultanei.

Overload principale GetOrCreateAsync

L'overload senza stato di GetOrCreateAsync è consigliato per la maggior parte degli scenari. Il codice da chiamare è relativamente semplice. Ecco un esempio:

public class SomeService(HybridCache cache)
{
    private HybridCache _cache = cache;

    public async Task<string> GetSomeInfoAsync(string name, int id, CancellationToken token = default)
    {
        return await _cache.GetOrCreateAsync(
            $"{name}-{id}", // Unique key to the cache entry
            async cancel => await GetDataFromTheSourceAsync(name, id, cancel),
            cancellationToken: token
        );
    }

    public async Task<string> GetDataFromTheSourceAsync(string name, int id, CancellationToken token)
    {
        string someInfo = $"someinfo-{name}-{id}";
        return someInfo;
    }
}

Overload alternativo GetOrCreateAsync

L'overload alternativo potrebbe ridurre il sovraccarico delle variabili acquisite e dei callback per istanza, ma a scapito di codice più complesso. Per la maggior parte degli scenari, l'aumento delle prestazioni non supera la complessità del codice. Ecco un esempio che usa l'overload alternativo:

public class SomeService(HybridCache cache)
{
    private HybridCache _cache = cache;

    public async Task<string> GetSomeInfoAsync(string name, int id, CancellationToken token = default)
    {
        return await _cache.GetOrCreateAsync(
            $"{name}-{id}", // Unique key to the cache entry
            (name, id, obj: this),
            static async (state, token) =>
            await state.obj.GetDataFromTheSourceAsync(state.name, state.id, token),
            cancellationToken: token
        );
    }

    public async Task<string> GetDataFromTheSourceAsync(string name, int id, CancellationToken token)
    {
        string someInfo = $"someinfo-{name}-{id}";
        return someInfo;
    }
}

Metodo SetAsync

In molti scenari, GetOrCreateAsync è l'unica API necessaria. Ma HybridCache deve SetAsync anche archiviare un oggetto nella cache senza tentare di recuperarlo per primo.

Rimuovere le voci della cache per chiave

Quando i dati sottostanti per una voce della cache vengono modificati prima della scadenza, rimuovere la voce in modo esplicito chiamando RemoveAsync con la chiave alla voce. Un overload consente di specificare una raccolta di valori chiave.

Quando una voce viene rimossa, viene rimossa dalle cache primarie e secondarie.

Rimuovere le voci della cache in base al tag

I tag possono essere usati per raggruppare le voci della cache e invalidarle insieme.

Impostare i tag quando si chiama GetOrCreateAsync, come illustrato nell'esempio seguente:

public class SomeService(HybridCache cache)
{
    private HybridCache _cache = cache;

    public async Task<string> GetSomeInfoAsync(string name, int id, CancellationToken token = default)
    {
        var tags = new List<string> { "tag1", "tag2", "tag3" };
        var entryOptions = new HybridCacheEntryOptions
        {
            Expiration = TimeSpan.FromMinutes(1),
            LocalCacheExpiration = TimeSpan.FromMinutes(1)
        };
        return await _cache.GetOrCreateAsync(
            $"{name}-{id}", // Unique key to the cache entry
            async cancel => await GetDataFromTheSourceAsync(name, id, cancel),
            entryOptions,
            tags,
            cancellationToken: token
        );
    }
    
    public async Task<string> GetDataFromTheSourceAsync(string name, int id, CancellationToken token)
    {
        string someInfo = $"someinfo-{name}-{id}";
        return someInfo;
    }
}

Rimuovere tutte le voci per un tag specificato chiamando RemoveByTagAsync con il valore del tag. Un overload consente di specificare una raccolta di valori di tag.

Quando una voce viene rimossa, viene rimossa dalle cache primarie e secondarie.

Opzioni

Il AddHybridCache metodo può essere usato per configurare le impostazioni predefinite globali. L'esempio seguente illustra come configurare alcune delle opzioni disponibili:

// Add services to the container.
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthorization();

builder.Services.AddHybridCache(options =>
    {
        options.MaximumPayloadBytes = 1024 * 1024;
        options.MaximumKeyLength = 1024;
        options.DefaultEntryOptions = new HybridCacheEntryOptions
        {
            Expiration = TimeSpan.FromMinutes(5),
            LocalCacheExpiration = TimeSpan.FromMinutes(5)
        };
    });

Il GetOrCreateAsync metodo può anche accettare un HybridCacheEntryOptions oggetto per eseguire l'override delle impostazioni predefinite globali per una voce di cache specifica. Ecco un esempio:

public class SomeService(HybridCache cache)
{
    private HybridCache _cache = cache;

    public async Task<string> GetSomeInfoAsync(string name, int id, CancellationToken token = default)
    {
        var tags = new List<string> { "tag1", "tag2", "tag3" };
        var entryOptions = new HybridCacheEntryOptions
        {
            Expiration = TimeSpan.FromMinutes(1),
            LocalCacheExpiration = TimeSpan.FromMinutes(1)
        };
        return await _cache.GetOrCreateAsync(
            $"{name}-{id}", // Unique key to the cache entry
            async cancel => await GetDataFromTheSourceAsync(name, id, cancel),
            entryOptions,
            tags,
            cancellationToken: token
        );
    }
    
    public async Task<string> GetDataFromTheSourceAsync(string name, int id, CancellationToken token)
    {
        string someInfo = $"someinfo-{name}-{id}";
        return someInfo;
    }
}

Per altre informazioni sulle opzioni, vedere il codice sorgente:

Limiti

Le proprietà seguenti di consentono di configurare i limiti applicabili a tutte le voci della HybridCacheOptions cache:

  • MaximumPayloadBytes: dimensione massima di una voce della cache. Il valore predefinito è 1 MB. I tentativi di archiviare i valori di questa dimensione vengono registrati e il valore non viene archiviato nella cache.
  • MaximumKeyLength: lunghezza massima di una chiave della cache. Il valore predefinito è 1024 caratteri. I tentativi di archiviare i valori di questa dimensione vengono registrati e il valore non viene archiviato nella cache.

Serializzazione

L'uso di una cache secondaria out-of-process richiede la serializzazione. La serializzazione viene configurata come parte della registrazione del HybridCache servizio. I serializzatori specifici del tipo e per utilizzo generico possono essere configurati tramite i AddSerializer metodi e AddSerializerFactory , concatenati dalla AddHybridCache chiamata. Per impostazione predefinita, la libreria gestisce string e byte[] internamente e usa System.Text.Json per tutto il resto. HybridCache può anche usare altri serializzatori, ad esempio protobuf o XML.

L'esempio seguente configura il servizio per l'uso di un serializzatore protobuf specifico del tipo:

// Add services to the container.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthorization();

builder.Services.AddHybridCache(options =>
    {
        options.DefaultEntryOptions = new HybridCacheEntryOptions
        {
            Expiration = TimeSpan.FromSeconds(10),
            LocalCacheExpiration = TimeSpan.FromSeconds(5)
        };
    }).AddSerializer<SomeProtobufMessage, 
        GoogleProtobufSerializer<SomeProtobufMessage>>();

L'esempio seguente configura il servizio per l'uso di un serializzatore protobuf per utilizzo generico in grado di gestire molti tipi protobuf:

// Add services to the container.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthorization();

builder.Services.AddHybridCache(options =>
{
    options.DefaultEntryOptions = new HybridCacheEntryOptions
    {
        Expiration = TimeSpan.FromSeconds(10),
        LocalCacheExpiration = TimeSpan.FromSeconds(5)
    };
}).AddSerializerFactory<GoogleProtobufSerializerFactory>();

La cache secondaria richiede un archivio dati, ad esempio Redis o SqlServer. Per usare cache di Azure per Redis, ad esempio:

  • Installare il pacchetto Microsoft.Extensions.Caching.StackExchangeRedis.

  • Creare un'istanza di cache di Azure per Redis.

  • Ottenere un stringa di connessione che si connette all'istanza di Redis. Trovare il stringa di connessione selezionando Mostra chiavi di accesso nella pagina Panoramica del portale di Azure.

  • Archiviare il stringa di connessione nella configurazione dell'app. Ad esempio, usare un file di segreti utente simile al codice JSON seguente, con il stringa di connessione nella ConnectionStrings sezione . Sostituire <the connection string> con il stringa di connessione effettivo:

    {
      "ConnectionStrings": {
        "RedisConnectionString": "<the connection string>"
      }
    }
    
  • Registrare nell'implementazione di inserimento delle dipendenze IDistributedCache fornita dal pacchetto Redis. A tale scopo, chiamare AddStackExchangeRedisCachee passare il stringa di connessione. Ad esempio:

    builder.Services.AddStackExchangeRedisCache(options =>
    {
        options.Configuration = 
            builder.Configuration.GetConnectionString("RedisConnectionString");
    });
    
  • L'implementazione di Redis IDistributedCache è ora disponibile dal contenitore di inserimento delle dipendenze dell'app. HybridCache lo usa come cache secondaria e usa il serializzatore configurato per tale cache.

Per altre informazioni, vedere l'app di esempio di serializzazione HybridCache.

Archiviazione cache

Per impostazione predefinita HybridCache , MemoryCache usa per l'archiviazione della cache primaria. Le voci della cache vengono archiviate in-process, quindi ogni server dispone di una cache separata che viene persa ogni volta che viene riavviato il processo del server. Per l'archiviazione out-of-process secondaria, ad esempio Redis o SQL Server, HybridCache usa l'implementazione configurataIDistributedCache, se presente. Ma anche senza un'implementazione IDistributedCache, il HybridCache servizio fornisce comunque la protezione in-process caching e stampede.

Ottimizzare le prestazioni

Per ottimizzare le prestazioni, configurare per riutilizzare HybridCache gli oggetti ed evitare byte[] allocazioni.

Riutilizzare gli oggetti

Riutilizzando istanze, HybridCache è possibile ridurre il sovraccarico delle allocazioni di CPU e oggetti associate alla deserializzazione per chiamata. Ciò può comportare miglioramenti delle prestazioni negli scenari in cui gli oggetti memorizzati nella cache sono di grandi dimensioni o a cui si accede di frequente.

Nel codice esistente tipico che usa IDistributedCache, ogni recupero di un oggetto dalla cache comporta la deserializzazione. Questo comportamento significa che ogni chiamante simultaneo ottiene un'istanza separata dell'oggetto, che non può interagire con altre istanze. Il risultato è thread safety, poiché non esiste alcun rischio di modifiche simultanee alla stessa istanza dell'oggetto.

Poiché gran parte HybridCache dell'utilizzo verrà adattato dal codice esistente IDistributedCache , HybridCache mantiene questo comportamento per impostazione predefinita per evitare di introdurre bug di concorrenza. Tuttavia, gli oggetti sono intrinsecamente thread-safe se:

  • Sono tipi non modificabili.
  • Il codice non li modifica.

In questi casi, informare HybridCache che è sicuro riutilizzare le istanze in base a:

  • Contrassegnare il tipo come sealed. La sealed parola chiave in C# indica che la classe non può essere ereditata.
  • Applicazione dell'attributo [ImmutableObject(true)] al tipo. L'attributo [ImmutableObject(true)] indica che lo stato dell'oggetto non può essere modificato dopo la creazione.

Evitare byte[] allocazioni

HybridCache fornisce anche API facoltative per IDistributedCache le implementazioni, per evitare byte[] allocazioni. Questa funzionalità viene implementata dalle versioni di anteprima dei Microsoft.Extensions.Caching.StackExchangeRedis pacchetti e Microsoft.Extensions.Caching.SqlServer . Per altre informazioni, vedere IBufferDistributedCache Ecco i comandi dell'interfaccia della riga di comando di .NET per installare i pacchetti:

dotnet add package Microsoft.Extensions.Caching.StackExchangeRedis --prerelease
dotnet add package Microsoft.Extensions.Caching.SqlServer --prerelease

Implementazioni di HybridCache personalizzate

Un'implementazione concreta della HybridCache classe astratta è inclusa nel framework condiviso e viene fornita tramite inserimento delle dipendenze. Gli sviluppatori sono tuttavia invitati a fornire implementazioni personalizzate dell'API.

Compatibilità

La HybridCache libreria supporta runtime .NET meno recenti, fino a .NET Framework 4.7.2 e .NET Standard 2.0.

Risorse aggiuntive

Per altre informazioni su HybridCache, vedere le risorse seguenti: